1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4 
5   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
6   All rights reserved.
7   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
8 
9      This software is distributed WITHOUT ANY WARRANTY; without even
10      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11      PURPOSE.  See the above copyright notice for more information.
12 
13 =========================================================================*/
14 #include "vtkOpenGLPointGaussianMapper.h"
15 
16 #include "vtkOpenGLHelper.h"
17 
18 #include "vtkBoundingBox.h"
19 #include "vtkCellArray.h"
20 #include "vtkCommand.h"
21 #include "vtkCompositeDataIterator.h"
22 #include "vtkCompositeDataPipeline.h"
23 #include "vtkCompositeDataSet.h"
24 #include "vtkDataObjectTreeIterator.h"
25 #include "vtkFloatArray.h"
26 #include "vtkGarbageCollector.h"
27 #include "vtkHardwareSelector.h"
28 #include "vtkInformation.h"
29 #include "vtkMath.h"
30 #include "vtkMatrix4x4.h"
31 #include "vtkObjectFactory.h"
32 #include "vtkOpenGLActor.h"
33 #include "vtkOpenGLCamera.h"
34 #include "vtkOpenGLIndexBufferObject.h"
35 #include "vtkOpenGLPolyDataMapper.h"
36 #include "vtkOpenGLRenderWindow.h"
37 #include "vtkOpenGLRenderer.h"
38 #include "vtkOpenGLState.h"
39 #include "vtkOpenGLVertexArrayObject.h"
40 #include "vtkOpenGLVertexBufferObject.h"
41 #include "vtkOpenGLVertexBufferObjectGroup.h"
42 #include "vtkPiecewiseFunction.h"
43 #include "vtkPointData.h"
44 #include "vtkPolyData.h"
45 #include "vtkProperty.h"
46 #include "vtkShaderProgram.h"
47 #include "vtkUnsignedCharArray.h"
48 
49 #include "vtkPointGaussianGS.h"
50 #include "vtkPointGaussianVS.h"
51 #include "vtkPolyDataFS.h"
52 
53 #include "vtk_glew.h"
54 
55 class vtkOpenGLPointGaussianMapperHelper : public vtkOpenGLPolyDataMapper
56 {
57 public:
58   static vtkOpenGLPointGaussianMapperHelper* New();
59   vtkTypeMacro(vtkOpenGLPointGaussianMapperHelper, vtkOpenGLPolyDataMapper);
60 
61   vtkPointGaussianMapper* Owner;
62 
63   // set from parent
64   float* OpacityTable;  // the table
65   double OpacityScale;  // used for quick lookups
66   double OpacityOffset; // used for quick lookups
67   float* ScaleTable;    // the table
68   double ScaleScale;    // used for quick lookups
69   double ScaleOffset;   // used for quick lookups
70 
71   vtkIdType FlatIndex;
72 
73   bool UsingPoints;
74   double TriangleScale;
75 
76   // called by our Owner skips some stuff
77   void GaussianRender(vtkRenderer* ren, vtkActor* act);
78 
79 protected:
80   vtkOpenGLPointGaussianMapperHelper();
81   ~vtkOpenGLPointGaussianMapperHelper() override;
82 
83   // Description:
84   // Create the basic shaders before replacement
85   void GetShaderTemplate(
86     std::map<vtkShader::Type, vtkShader*> shaders, vtkRenderer*, vtkActor*) override;
87 
88   // Description:
89   // Perform string replacements on the shader templates
90   void ReplaceShaderColor(
91     std::map<vtkShader::Type, vtkShader*> shaders, vtkRenderer*, vtkActor*) override;
92   void ReplaceShaderPositionVC(
93     std::map<vtkShader::Type, vtkShader*> shaders, vtkRenderer*, vtkActor*) override;
94 
95   // Description:
96   // Set the shader parameters related to the Camera
97   void SetCameraShaderParameters(vtkOpenGLHelper& cellBO, vtkRenderer* ren, vtkActor* act) override;
98 
99   // Description:
100   // Set the shader parameters related to the actor/mapper
101   void SetMapperShaderParameters(vtkOpenGLHelper& cellBO, vtkRenderer* ren, vtkActor* act) override;
102 
103   // Description:
104   // Does the VBO/IBO need to be rebuilt
105   bool GetNeedToRebuildBufferObjects(vtkRenderer* ren, vtkActor* act) override;
106 
107   // Description:
108   // Update the VBO to contain point based values
109   void BuildBufferObjects(vtkRenderer* ren, vtkActor* act) override;
110 
111   void RenderPieceDraw(vtkRenderer* ren, vtkActor* act) override;
112 
113   // Description:
114   // Does the shader source need to be recomputed
115   bool GetNeedToRebuildShaders(vtkOpenGLHelper& cellBO, vtkRenderer* ren, vtkActor* act) override;
116 
117 private:
118   vtkOpenGLPointGaussianMapperHelper(const vtkOpenGLPointGaussianMapperHelper&) = delete;
119   void operator=(const vtkOpenGLPointGaussianMapperHelper&) = delete;
120 };
121 
122 //------------------------------------------------------------------------------
123 vtkStandardNewMacro(vtkOpenGLPointGaussianMapperHelper);
124 
125 //------------------------------------------------------------------------------
vtkOpenGLPointGaussianMapperHelper()126 vtkOpenGLPointGaussianMapperHelper::vtkOpenGLPointGaussianMapperHelper()
127 {
128   this->Owner = nullptr;
129   this->UsingPoints = false;
130   this->TriangleScale = 0.0;
131   this->FlatIndex = 1;
132   this->OpacityTable = nullptr;
133   this->ScaleTable = nullptr;
134   this->OpacityScale = 1.0;
135   this->ScaleScale = 1.0;
136   this->OpacityOffset = 0.0;
137   this->ScaleOffset = 0.0;
138 }
139 
140 //------------------------------------------------------------------------------
GetShaderTemplate(std::map<vtkShader::Type,vtkShader * > shaders,vtkRenderer * ren,vtkActor * actor)141 void vtkOpenGLPointGaussianMapperHelper::GetShaderTemplate(
142   std::map<vtkShader::Type, vtkShader*> shaders, vtkRenderer* ren, vtkActor* actor)
143 {
144   this->Superclass::GetShaderTemplate(shaders, ren, actor);
145 
146   if (this->Owner->GetScaleFactor() == 0.0)
147   {
148     this->UsingPoints = true;
149   }
150   else
151   {
152     this->UsingPoints = false;
153     // for splats use a special shader that handles the offsets
154     shaders[vtkShader::Vertex]->SetSource(vtkPointGaussianVS);
155     shaders[vtkShader::Geometry]->SetSource(vtkPointGaussianGS);
156   }
157 }
158 
ReplaceShaderPositionVC(std::map<vtkShader::Type,vtkShader * > shaders,vtkRenderer * ren,vtkActor * actor)159 void vtkOpenGLPointGaussianMapperHelper::ReplaceShaderPositionVC(
160   std::map<vtkShader::Type, vtkShader*> shaders, vtkRenderer* ren, vtkActor* actor)
161 {
162   if (!this->UsingPoints)
163   {
164     std::string VSSource = shaders[vtkShader::Vertex]->GetSource();
165     std::string FSSource = shaders[vtkShader::Fragment]->GetSource();
166 
167     vtkShaderProgram::Substitute(FSSource, "//VTK::PositionVC::Dec", "in vec2 offsetVCVSOutput;");
168 
169     vtkShaderProgram::Substitute(VSSource, "//VTK::Camera::Dec",
170       "uniform mat4 VCDCMatrix;\n"
171       "uniform mat4 MCVCMatrix;");
172 
173     shaders[vtkShader::Vertex]->SetSource(VSSource);
174     shaders[vtkShader::Fragment]->SetSource(FSSource);
175   }
176 
177   this->Superclass::ReplaceShaderPositionVC(shaders, ren, actor);
178 }
179 
ReplaceShaderColor(std::map<vtkShader::Type,vtkShader * > shaders,vtkRenderer * ren,vtkActor * actor)180 void vtkOpenGLPointGaussianMapperHelper::ReplaceShaderColor(
181   std::map<vtkShader::Type, vtkShader*> shaders, vtkRenderer* ren, vtkActor* actor)
182 {
183   if (!this->UsingPoints)
184   {
185     std::string FSSource = shaders[vtkShader::Fragment]->GetSource();
186 
187     if (this->Owner->GetSplatShaderCode() && strcmp(this->Owner->GetSplatShaderCode(), "") != 0)
188     {
189       vtkShaderProgram::Substitute(
190         FSSource, "//VTK::Color::Impl", this->Owner->GetSplatShaderCode(), false);
191     }
192     else
193     {
194       vtkShaderProgram::Substitute(FSSource, "//VTK::Color::Impl",
195         // compute the eye position and unit direction
196         "//VTK::Color::Impl\n"
197         "  float dist2 = dot(offsetVCVSOutput.xy,offsetVCVSOutput.xy);\n"
198         "  float gaussian = exp(-0.5*dist2);\n"
199         "  opacity = opacity*gaussian;"
200         //  "  opacity = opacity*0.5;"
201         ,
202         false);
203     }
204     shaders[vtkShader::Fragment]->SetSource(FSSource);
205   }
206 
207   this->Superclass::ReplaceShaderColor(shaders, ren, actor);
208   // cerr << shaders[vtkShader::Fragment]->GetSource() << endl;
209 }
210 
211 //------------------------------------------------------------------------------
GetNeedToRebuildShaders(vtkOpenGLHelper & cellBO,vtkRenderer * ren,vtkActor * actor)212 bool vtkOpenGLPointGaussianMapperHelper::GetNeedToRebuildShaders(
213   vtkOpenGLHelper& cellBO, vtkRenderer* ren, vtkActor* actor)
214 {
215   this->PrimitiveInfo[&cellBO].LastLightComplexity = 0;
216 
217   vtkHardwareSelector* selector = ren->GetSelector();
218   int picking = selector ? selector->GetCurrentPass() : -1;
219   if (this->LastSelectionState != picking)
220   {
221     this->SelectionStateChanged.Modified();
222     this->LastSelectionState = picking;
223   }
224 
225   vtkMTimeType renderPassMTime = this->GetRenderPassStageMTime(actor, &cellBO);
226 
227   // has something changed that would require us to recreate the shader?
228   // candidates are
229   // property modified (representation interpolation and lighting)
230   // input modified
231   // light complexity changed
232   if (cellBO.Program == nullptr || cellBO.ShaderSourceTime < this->GetMTime() ||
233     cellBO.ShaderSourceTime < actor->GetMTime() ||
234     cellBO.ShaderSourceTime < this->CurrentInput->GetMTime() ||
235     cellBO.ShaderSourceTime < this->SelectionStateChanged ||
236     cellBO.ShaderSourceTime < renderPassMTime)
237   {
238     return true;
239   }
240 
241   return false;
242 }
243 
244 //------------------------------------------------------------------------------
245 vtkOpenGLPointGaussianMapperHelper::~vtkOpenGLPointGaussianMapperHelper() = default;
246 
247 //------------------------------------------------------------------------------
SetCameraShaderParameters(vtkOpenGLHelper & cellBO,vtkRenderer * ren,vtkActor * actor)248 void vtkOpenGLPointGaussianMapperHelper::SetCameraShaderParameters(
249   vtkOpenGLHelper& cellBO, vtkRenderer* ren, vtkActor* actor)
250 {
251   if (this->UsingPoints)
252   {
253     this->Superclass::SetCameraShaderParameters(cellBO, ren, actor);
254   }
255   else
256   {
257     vtkShaderProgram* program = cellBO.Program;
258 
259     vtkOpenGLCamera* cam = (vtkOpenGLCamera*)(ren->GetActiveCamera());
260 
261     vtkMatrix4x4* wcdc;
262     vtkMatrix4x4* wcvc;
263     vtkMatrix3x3* norms;
264     vtkMatrix4x4* vcdc;
265     cam->GetKeyMatrices(ren, wcvc, norms, vcdc, wcdc);
266     program->SetUniformMatrix("VCDCMatrix", vcdc);
267 
268     if (!actor->GetIsIdentity())
269     {
270       vtkMatrix4x4* mcwc;
271       vtkMatrix3x3* anorms;
272       ((vtkOpenGLActor*)actor)->GetKeyMatrices(mcwc, anorms);
273       vtkMatrix4x4::Multiply4x4(mcwc, wcvc, this->TempMatrix4);
274       program->SetUniformMatrix("MCVCMatrix", this->TempMatrix4);
275     }
276     else
277     {
278       program->SetUniformMatrix("MCVCMatrix", wcvc);
279     }
280 
281     // add in uniforms for parallel and distance
282     cellBO.Program->SetUniformi("cameraParallel", cam->GetParallelProjection());
283   }
284 }
285 
286 //------------------------------------------------------------------------------
SetMapperShaderParameters(vtkOpenGLHelper & cellBO,vtkRenderer * ren,vtkActor * actor)287 void vtkOpenGLPointGaussianMapperHelper::SetMapperShaderParameters(
288   vtkOpenGLHelper& cellBO, vtkRenderer* ren, vtkActor* actor)
289 {
290   if (!this->UsingPoints)
291   {
292     cellBO.Program->SetUniformf("triangleScale", this->TriangleScale);
293   }
294   this->Superclass::SetMapperShaderParameters(cellBO, ren, actor);
295 }
296 
297 namespace
298 {
299 
300 template <typename PointDataType>
vtkOpenGLPointGaussianMapperHelperGetComponent(PointDataType * tuple,int nComponent,int component)301 PointDataType vtkOpenGLPointGaussianMapperHelperGetComponent(
302   PointDataType* tuple, int nComponent, int component)
303 {
304   // If this is a single component array, make sure we do not compute
305   // a useless magnitude
306   if (nComponent == 1)
307   {
308     component = 0;
309   }
310 
311   // If we request a non-existing componeent, return the magnitude of the tuple
312   PointDataType compVal = 0.0;
313   if (component < 0 || component >= nComponent)
314   {
315     for (int iComp = 0; iComp < nComponent; iComp++)
316     {
317       PointDataType tmp = tuple[iComp];
318       compVal += tmp * tmp;
319     }
320     compVal = sqrt(compVal);
321   }
322   else
323   {
324     compVal = tuple[component];
325   }
326   return compVal;
327 }
328 
vtkOpenGLPointGaussianMapperHelperComputeColor(unsigned char * rcolor,unsigned char * colors,int colorComponents,vtkIdType index,vtkDataArray * opacities,int opacitiesComponent,vtkOpenGLPointGaussianMapperHelper * self)329 void vtkOpenGLPointGaussianMapperHelperComputeColor(unsigned char* rcolor, unsigned char* colors,
330   int colorComponents, vtkIdType index, vtkDataArray* opacities, int opacitiesComponent,
331   vtkOpenGLPointGaussianMapperHelper* self)
332 {
333   unsigned char white[4] = { 255, 255, 255, 255 };
334 
335   // if there are no per point sizes and the default size is zero
336   // then just render points, saving memory and speed
337   unsigned char* colorPtr = colors ? (colors + index * colorComponents) : white;
338   rcolor[0] = *(colorPtr++);
339   rcolor[1] = *(colorPtr++);
340   rcolor[2] = *(colorPtr++);
341 
342   if (opacities)
343   {
344     double opacity = vtkOpenGLPointGaussianMapperHelperGetComponent<double>(
345       opacities->GetTuple(index), opacities->GetNumberOfComponents(), opacitiesComponent);
346     if (self->OpacityTable)
347     {
348       double tindex = (opacity - self->OpacityOffset) * self->OpacityScale;
349       int itindex = static_cast<int>(tindex);
350       if (itindex >= self->Owner->GetOpacityTableSize() - 1)
351       {
352         opacity = self->OpacityTable[self->Owner->GetOpacityTableSize() - 1];
353       }
354       else if (itindex < 0)
355       {
356         opacity = self->OpacityTable[0];
357       }
358       else
359       {
360         opacity = (1.0 - tindex + itindex) * self->OpacityTable[itindex] +
361           (tindex - itindex) * self->OpacityTable[itindex + 1];
362       }
363     }
364     rcolor[3] = static_cast<float>(opacity * 255.0);
365   }
366   else
367   {
368     rcolor[3] = (colorComponents == 4 ? *colorPtr : 255);
369   }
370 }
371 
vtkOpenGLPointGaussianMapperHelperColors(vtkUnsignedCharArray * outColors,vtkIdType numPts,unsigned char * colors,int colorComponents,vtkDataArray * opacities,int opacitiesComponent,vtkOpenGLPointGaussianMapperHelper * self,vtkCellArray * verts)372 void vtkOpenGLPointGaussianMapperHelperColors(vtkUnsignedCharArray* outColors, vtkIdType numPts,
373   unsigned char* colors, int colorComponents, vtkDataArray* opacities, int opacitiesComponent,
374   vtkOpenGLPointGaussianMapperHelper* self, vtkCellArray* verts)
375 {
376   unsigned char* vPtr = static_cast<unsigned char*>(outColors->GetVoidPointer(0));
377 
378   // iterate over cells or not
379   if (verts->GetNumberOfCells())
380   {
381     const vtkIdType* indices(nullptr);
382     vtkIdType npts(0);
383     for (verts->InitTraversal(); verts->GetNextCell(npts, indices);)
384     {
385       for (int i = 0; i < npts; ++i)
386       {
387         vtkOpenGLPointGaussianMapperHelperComputeColor(
388           vPtr, colors, colorComponents, indices[i], opacities, opacitiesComponent, self);
389         vPtr += 4;
390       }
391     }
392   }
393   else
394   {
395     for (vtkIdType i = 0; i < numPts; i++)
396     {
397       vtkOpenGLPointGaussianMapperHelperComputeColor(
398         vPtr, colors, colorComponents, i, opacities, opacitiesComponent, self);
399       vPtr += 4;
400     }
401   }
402 }
403 
vtkOpenGLPointGaussianMapperHelperGetRadius(double radius,vtkOpenGLPointGaussianMapperHelper * self)404 float vtkOpenGLPointGaussianMapperHelperGetRadius(
405   double radius, vtkOpenGLPointGaussianMapperHelper* self)
406 {
407   if (self->ScaleTable)
408   {
409     double tindex = (radius - self->ScaleOffset) * self->ScaleScale;
410     int itindex = static_cast<int>(tindex);
411     if (itindex >= self->Owner->GetScaleTableSize() - 1)
412     {
413       radius = self->ScaleTable[self->Owner->GetScaleTableSize() - 1];
414     }
415     else if (itindex < 0)
416     {
417       radius = self->ScaleTable[0];
418     }
419     else
420     {
421       radius = (1.0 - tindex + itindex) * self->ScaleTable[itindex] +
422         (tindex - itindex) * self->ScaleTable[itindex + 1];
423     }
424   }
425   radius *= self->Owner->GetScaleFactor();
426   radius *= self->TriangleScale;
427 
428   return static_cast<float>(radius);
429 }
430 
431 template <typename PointDataType>
vtkOpenGLPointGaussianMapperHelperSizes(vtkFloatArray * scales,PointDataType * sizes,int nComponent,int component,vtkIdType numPts,vtkOpenGLPointGaussianMapperHelper * self,vtkCellArray * verts)432 void vtkOpenGLPointGaussianMapperHelperSizes(vtkFloatArray* scales, PointDataType* sizes,
433   int nComponent, int component, vtkIdType numPts, vtkOpenGLPointGaussianMapperHelper* self,
434   vtkCellArray* verts)
435 {
436   float* it = static_cast<float*>(scales->GetVoidPointer(0));
437 
438   // iterate over cells or not
439   if (verts->GetNumberOfCells())
440   {
441     const vtkIdType* indices(nullptr);
442     vtkIdType npts(0);
443     for (verts->InitTraversal(); verts->GetNextCell(npts, indices);)
444     {
445       for (vtkIdType i = 0; i < npts; ++i)
446       {
447         PointDataType size = 1.0;
448         if (sizes)
449         {
450           size = vtkOpenGLPointGaussianMapperHelperGetComponent<PointDataType>(
451             &sizes[indices[i] * nComponent], nComponent, component);
452         }
453         float radiusFloat = vtkOpenGLPointGaussianMapperHelperGetRadius(size, self);
454         *(it++) = radiusFloat;
455       }
456     }
457   }
458   else
459   {
460     for (vtkIdType i = 0; i < numPts; i++)
461     {
462       PointDataType size = 1.0;
463       if (sizes)
464       {
465         size = vtkOpenGLPointGaussianMapperHelperGetComponent<PointDataType>(
466           &sizes[i * nComponent], nComponent, component);
467       }
468       float radiusFloat = vtkOpenGLPointGaussianMapperHelperGetRadius(size, self);
469       *(it++) = radiusFloat;
470     }
471   }
472 }
473 
474 } // anonymous namespace
475 
476 //------------------------------------------------------------------------------
GetNeedToRebuildBufferObjects(vtkRenderer * vtkNotUsed (ren),vtkActor * act)477 bool vtkOpenGLPointGaussianMapperHelper::GetNeedToRebuildBufferObjects(
478   vtkRenderer* vtkNotUsed(ren), vtkActor* act)
479 {
480   if (this->VBOBuildTime < this->GetMTime() || this->VBOBuildTime < act->GetMTime() ||
481     this->VBOBuildTime < this->CurrentInput->GetMTime() ||
482     this->VBOBuildTime < this->Owner->GetMTime() ||
483     (this->Owner->GetScalarOpacityFunction() &&
484       this->VBOBuildTime < this->Owner->GetScalarOpacityFunction()->GetMTime()) ||
485     (this->Owner->GetScaleFunction() &&
486       this->VBOBuildTime < this->Owner->GetScaleFunction()->GetMTime()))
487   {
488     return true;
489   }
490   return false;
491 }
492 
493 //------------------------------------------------------------------------------
BuildBufferObjects(vtkRenderer * ren,vtkActor * vtkNotUsed (act))494 void vtkOpenGLPointGaussianMapperHelper::BuildBufferObjects(
495   vtkRenderer* ren, vtkActor* vtkNotUsed(act))
496 {
497   vtkPolyData* poly = this->CurrentInput;
498 
499   if (poly == nullptr)
500   {
501     return;
502   }
503 
504   // set the triangle scale
505   this->TriangleScale = this->Owner->GetTriangleScale();
506 
507   bool hasScaleArray = this->Owner->GetScaleArray() != nullptr &&
508     poly->GetPointData()->HasArray(this->Owner->GetScaleArray());
509 
510   if (this->Owner->GetScaleFactor() == 0.0)
511   {
512     this->UsingPoints = true;
513   }
514   else
515   {
516     this->UsingPoints = false;
517   }
518 
519   // if we have an opacity array then get it and if we have
520   // a ScalarOpacityFunction map the array through it
521   bool hasOpacityArray = this->Owner->GetOpacityArray() != nullptr &&
522     poly->GetPointData()->HasArray(this->Owner->GetOpacityArray());
523 
524   // For vertex coloring, this sets this->Colors as side effect.
525   // For texture map coloring, this sets ColorCoordinates
526   // and ColorTextureMap as a side effect.
527   // I moved this out of the conditional because it is fast.
528   // Color arrays are cached. If nothing has changed,
529   // then the scalars do not have to be regenerted.
530   this->MapScalars(1.0);
531 
532   int splatCount = poly->GetPoints()->GetNumberOfPoints();
533   if (poly->GetVerts()->GetNumberOfCells())
534   {
535     splatCount = poly->GetVerts()->GetNumberOfConnectivityIds();
536   }
537 
538   // need to build points?
539   if (poly->GetVerts()->GetNumberOfCells())
540   {
541     vtkFloatArray* pts = vtkFloatArray::New();
542     pts->SetNumberOfComponents(3);
543     pts->SetNumberOfTuples(splatCount);
544 
545     auto srcData = poly->GetPoints()->GetData();
546     const auto srcTuples = vtk::DataArrayTupleRange<3>(srcData);
547     auto dstTuples = vtk::DataArrayTupleRange<3>(pts);
548     auto dstIter = dstTuples.begin();
549     auto verts = poly->GetVerts();
550     const vtkIdType* indices(nullptr);
551     vtkIdType npts(0);
552     for (verts->InitTraversal(); verts->GetNextCell(npts, indices);)
553     {
554       for (vtkIdType i = 0; i < npts; ++i)
555       {
556         auto srcIter = srcTuples[indices[i]];
557         auto dst = *dstIter;
558         dst[0] = srcIter[0];
559         dst[1] = srcIter[1];
560         dst[2] = srcIter[2];
561         ++dstIter;
562       }
563     }
564 
565     this->VBOs->CacheDataArray("vertexMC", pts, ren, VTK_FLOAT);
566     pts->Delete();
567   }
568   else // just pass the points
569   {
570     this->VBOs->CacheDataArray("vertexMC", poly->GetPoints()->GetData(), ren, VTK_FLOAT);
571   }
572 
573   if (!this->UsingPoints)
574   {
575     vtkFloatArray* offsets = vtkFloatArray::New();
576     offsets->SetNumberOfComponents(1);
577     offsets->SetNumberOfTuples(splatCount);
578 
579     if (hasScaleArray)
580     {
581       vtkDataArray* sizes = poly->GetPointData()->GetArray(this->Owner->GetScaleArray());
582       switch (sizes->GetDataType())
583       {
584         vtkTemplateMacro(vtkOpenGLPointGaussianMapperHelperSizes(offsets,
585           static_cast<VTK_TT*>(sizes->GetVoidPointer(0)), sizes->GetNumberOfComponents(),
586           this->Owner->GetScaleArrayComponent(), poly->GetPoints()->GetNumberOfPoints(), this,
587           poly->GetVerts()));
588       }
589     }
590     else
591     {
592       vtkOpenGLPointGaussianMapperHelperSizes(offsets, static_cast<float*>(nullptr), 0, 0,
593         poly->GetPoints()->GetNumberOfPoints(), this, poly->GetVerts());
594     }
595     this->VBOs->CacheDataArray("radiusMC", offsets, ren, VTK_FLOAT);
596     offsets->Delete();
597   }
598   else
599   {
600     this->VBOs->CacheDataArray("radiusMC", nullptr, ren, VTK_FLOAT);
601   }
602 
603   if (this->Colors)
604   {
605     vtkUnsignedCharArray* clrs = vtkUnsignedCharArray::New();
606     clrs->SetNumberOfComponents(4);
607     clrs->SetNumberOfTuples(splatCount);
608 
609     vtkOpenGLPointGaussianMapperHelperColors(clrs, poly->GetPoints()->GetNumberOfPoints(),
610       this->Colors ? (unsigned char*)this->Colors->GetVoidPointer(0) : (unsigned char*)nullptr,
611       this->Colors ? this->Colors->GetNumberOfComponents() : 0,
612       hasOpacityArray ? poly->GetPointData()->GetArray(this->Owner->GetOpacityArray())
613                       : (vtkDataArray*)nullptr,
614       this->Owner->GetOpacityArrayComponent(), this, poly->GetVerts());
615     this->VBOs->CacheDataArray("scalarColor", clrs, ren, VTK_UNSIGNED_CHAR);
616     clrs->Delete();
617   }
618 
619   this->VBOs->BuildAllVBOs(ren);
620 
621   // we use no IBO
622   for (int i = PrimitiveStart; i < PrimitiveEnd; i++)
623   {
624     this->Primitives[i].IBO->IndexCount = 0;
625   }
626   this->Primitives[PrimitiveTris].IBO->IndexCount = splatCount;
627   this->VBOBuildTime.Modified();
628 }
629 
630 //------------------------------------------------------------------------------
RenderPieceDraw(vtkRenderer * ren,vtkActor * actor)631 void vtkOpenGLPointGaussianMapperHelper::RenderPieceDraw(vtkRenderer* ren, vtkActor* actor)
632 {
633   // draw polygons
634   int numVerts = this->VBOs->GetNumberOfTuples("vertexMC");
635   if (numVerts)
636   {
637     this->UpdateShaders(this->Primitives[PrimitiveTris], ren, actor);
638     glDrawArrays(GL_POINTS, 0, static_cast<GLuint>(numVerts));
639   }
640 }
641 
642 namespace
643 {
644 // helper to get the state of picking
getPickState(vtkRenderer * ren)645 int getPickState(vtkRenderer* ren)
646 {
647   vtkHardwareSelector* selector = ren->GetSelector();
648   if (selector)
649   {
650     return selector->GetCurrentPass();
651   }
652 
653   return vtkHardwareSelector::MIN_KNOWN_PASS - 1;
654 }
655 }
656 
657 //------------------------------------------------------------------------------
GaussianRender(vtkRenderer * ren,vtkActor * actor)658 void vtkOpenGLPointGaussianMapperHelper::GaussianRender(vtkRenderer* ren, vtkActor* actor)
659 {
660   int picking = getPickState(ren);
661   if (this->LastSelectionState != picking)
662   {
663     this->SelectionStateChanged.Modified();
664     this->LastSelectionState = picking;
665   }
666 
667   this->LastBoundBO = nullptr;
668   this->CurrentInput = this->GetInput();
669 
670   this->UpdateBufferObjects(ren, actor);
671   this->RenderPieceDraw(ren, actor);
672 
673   if (this->LastBoundBO)
674   {
675     this->LastBoundBO->VAO->Release();
676   }
677 }
678 
679 //------------------------------------------------------------------------------
680 vtkStandardNewMacro(vtkOpenGLPointGaussianMapper);
681 
682 //------------------------------------------------------------------------------
vtkOpenGLPointGaussianMapper()683 vtkOpenGLPointGaussianMapper::vtkOpenGLPointGaussianMapper()
684 {
685   this->OpacityTable = nullptr;
686   this->ScaleTable = nullptr;
687   this->OpacityScale = 1.0;
688   this->ScaleScale = 1.0;
689   this->OpacityOffset = 0.0;
690   this->ScaleOffset = 0.0;
691 }
692 
~vtkOpenGLPointGaussianMapper()693 vtkOpenGLPointGaussianMapper::~vtkOpenGLPointGaussianMapper()
694 {
695   if (this->OpacityTable)
696   {
697     delete[] this->OpacityTable;
698     this->OpacityTable = nullptr;
699   }
700   if (this->ScaleTable)
701   {
702     delete[] this->ScaleTable;
703     this->ScaleTable = nullptr;
704   }
705 
706   // clear old helpers carefully due to garbage collection loops
707   for (auto hiter = this->Helpers.begin(); hiter != this->Helpers.end(); ++hiter)
708   {
709     // these pointers may be set to nullptr by the garbage collector
710     // since we are passing them in using ReportReferences
711     if (*hiter)
712     {
713       (*hiter)->Delete();
714     }
715   }
716   this->Helpers.clear();
717 }
718 
ReportReferences(vtkGarbageCollector * collector)719 void vtkOpenGLPointGaussianMapper::ReportReferences(vtkGarbageCollector* collector)
720 {
721   // Report references held by this object that may be in a loop.
722   this->Superclass::ReportReferences(collector);
723 
724   // helpers is a vector
725   for (auto hiter = this->Helpers.begin(); hiter != this->Helpers.end(); ++hiter)
726   {
727     vtkGarbageCollectorReport(collector, *hiter, "vtkOpenGLPointGaussianMapperHelper");
728   }
729 }
730 
Render(vtkRenderer * ren,vtkActor * actor)731 void vtkOpenGLPointGaussianMapper::Render(vtkRenderer* ren, vtkActor* actor)
732 {
733   // Make sure that we have been properly initialized.
734   if (ren->GetRenderWindow()->CheckAbortStatus())
735   {
736     return;
737   }
738 
739   if (this->GetInputAlgorithm() == nullptr)
740   {
741     return;
742   }
743 
744   if (!this->Static)
745   {
746     this->InvokeEvent(vtkCommand::StartEvent, nullptr);
747     this->GetInputAlgorithm()->Update();
748     this->InvokeEvent(vtkCommand::EndEvent, nullptr);
749   }
750 
751   if (this->GetInputDataObject(0, 0) == nullptr)
752   {
753     vtkErrorMacro(<< "No input!");
754     return;
755   }
756 
757   // update tables
758   if (this->GetScaleFunction() && this->GetScaleArray())
759   {
760     if (this->ScaleTableUpdateTime < this->GetScaleFunction()->GetMTime() ||
761       this->ScaleTableUpdateTime < this->GetMTime())
762     {
763       this->BuildScaleTable();
764       this->ScaleTableUpdateTime.Modified();
765     }
766   }
767   else
768   {
769     delete[] this->ScaleTable;
770     this->ScaleTable = nullptr;
771   }
772 
773   if (this->GetScalarOpacityFunction() && this->GetOpacityArray())
774   {
775     if (this->OpacityTableUpdateTime < this->GetScalarOpacityFunction()->GetMTime() ||
776       this->OpacityTableUpdateTime < this->GetMTime())
777     {
778       this->BuildOpacityTable();
779       this->OpacityTableUpdateTime.Modified();
780     }
781   }
782   else
783   {
784     delete[] this->OpacityTable;
785     this->OpacityTable = nullptr;
786   }
787 
788   // the first step is to update the helpers if needed
789   if (this->HelperUpdateTime < this->GetInputDataObject(0, 0)->GetMTime() ||
790     this->HelperUpdateTime < this->GetInputAlgorithm()->GetMTime() ||
791     this->HelperUpdateTime < this->GetMTime())
792   {
793     // clear old helpers
794     for (auto hiter = this->Helpers.begin(); hiter != this->Helpers.end(); ++hiter)
795     {
796       (*hiter)->Delete();
797     }
798     this->Helpers.clear();
799 
800     // build new helpers
801     vtkCompositeDataSet* input = vtkCompositeDataSet::SafeDownCast(this->GetInputDataObject(0, 0));
802 
803     if (input)
804     {
805       vtkSmartPointer<vtkDataObjectTreeIterator> iter =
806         vtkSmartPointer<vtkDataObjectTreeIterator>::New();
807       iter->SetDataSet(input);
808       iter->SkipEmptyNodesOn();
809       iter->VisitOnlyLeavesOn();
810       for (iter->InitTraversal(); !iter->IsDoneWithTraversal(); iter->GoToNextItem())
811       {
812         unsigned int flatIndex = iter->GetCurrentFlatIndex();
813         vtkDataObject* dso = iter->GetCurrentDataObject();
814         vtkPolyData* pd = vtkPolyData::SafeDownCast(dso);
815 
816         if (!pd || !pd->GetPoints())
817         {
818           continue;
819         }
820 
821         vtkOpenGLPointGaussianMapperHelper* helper = this->CreateHelper();
822         this->CopyMapperValuesToHelper(helper);
823         helper->SetInputData(pd);
824         helper->FlatIndex = flatIndex;
825         this->Helpers.push_back(helper);
826       }
827     }
828     else
829     {
830       vtkPolyData* pd = vtkPolyData::SafeDownCast(this->GetInputDataObject(0, 0));
831       if (pd && pd->GetPoints())
832       {
833         vtkOpenGLPointGaussianMapperHelper* helper = this->CreateHelper();
834         this->CopyMapperValuesToHelper(helper);
835         helper->SetInputData(pd);
836         this->Helpers.push_back(helper);
837       }
838     }
839 
840     this->HelperUpdateTime.Modified();
841   }
842 
843   if (this->Emissive != 0 && !ren->GetSelector())
844   {
845     vtkOpenGLState* ostate = static_cast<vtkOpenGLRenderer*>(ren)->GetState();
846     vtkOpenGLState::ScopedglBlendFuncSeparate bfsaver(ostate);
847     ostate->vtkglDepthMask(GL_FALSE);
848     ostate->vtkglBlendFunc(GL_SRC_ALPHA, GL_ONE); // additive for emissive sources
849     this->RenderInternal(ren, actor);
850   }
851   else // intentional else due to scope
852   {
853     this->RenderInternal(ren, actor);
854   }
855 }
856 
857 // this could be made much faster for composite
858 // datasets that have lots of small blocks
859 // but for now we just want to add the functionality
RenderInternal(vtkRenderer * ren,vtkActor * actor)860 void vtkOpenGLPointGaussianMapper::RenderInternal(vtkRenderer* ren, vtkActor* actor)
861 {
862   // Set the PointSize
863   vtkOpenGLRenderWindow* renWin = static_cast<vtkOpenGLRenderWindow*>(ren->GetRenderWindow());
864   vtkOpenGLState* ostate = renWin->GetState();
865   ostate->vtkglPointSize(actor->GetProperty()->GetPointSize());
866 
867   // render points for point picking in a special way
868   vtkHardwareSelector* selector = ren->GetSelector();
869   if (selector && selector->GetFieldAssociation() == vtkDataObject::FIELD_ASSOCIATION_POINTS)
870   {
871     static_cast<vtkOpenGLRenderer*>(ren)->GetState()->vtkglDepthMask(GL_FALSE);
872   }
873 
874   if (selector)
875   {
876     selector->BeginRenderProp();
877   }
878 
879   for (auto hiter = this->Helpers.begin(); hiter != this->Helpers.end(); ++hiter)
880   {
881     // make sure the BOs are up to date
882     vtkOpenGLPointGaussianMapperHelper* helper = *hiter;
883     if (selector && selector->GetCurrentPass() == vtkHardwareSelector::COMPOSITE_INDEX_PASS)
884     {
885       selector->RenderCompositeIndex(helper->FlatIndex);
886     }
887     helper->GaussianRender(ren, actor);
888   }
889 
890   // reset picking
891   if (selector && selector->GetFieldAssociation() == vtkDataObject::FIELD_ASSOCIATION_POINTS)
892   {
893     static_cast<vtkOpenGLRenderer*>(ren)->GetState()->vtkglDepthMask(GL_TRUE);
894   }
895   if (selector)
896   {
897     selector->EndRenderProp();
898   }
899 
900   this->UpdateProgress(1.0);
901 }
902 
CreateHelper()903 vtkOpenGLPointGaussianMapperHelper* vtkOpenGLPointGaussianMapper::CreateHelper()
904 {
905   auto helper = vtkOpenGLPointGaussianMapperHelper::New();
906   helper->Owner = this;
907   return helper;
908 }
909 
CopyMapperValuesToHelper(vtkOpenGLPointGaussianMapperHelper * helper)910 void vtkOpenGLPointGaussianMapper::CopyMapperValuesToHelper(
911   vtkOpenGLPointGaussianMapperHelper* helper)
912 {
913   helper->vtkPolyDataMapper::ShallowCopy(this);
914   helper->OpacityTable = this->OpacityTable;
915   helper->OpacityScale = this->OpacityScale;
916   helper->OpacityOffset = this->OpacityOffset;
917   helper->ScaleTable = this->ScaleTable;
918   helper->ScaleScale = this->ScaleScale;
919   helper->ScaleOffset = this->ScaleOffset;
920   helper->Modified();
921 }
922 
923 //------------------------------------------------------------------------------
ReleaseGraphicsResources(vtkWindow * win)924 void vtkOpenGLPointGaussianMapper::ReleaseGraphicsResources(vtkWindow* win)
925 {
926   for (auto hiter = this->Helpers.begin(); hiter != this->Helpers.end(); ++hiter)
927   {
928     (*hiter)->ReleaseGraphicsResources(win);
929   }
930 
931   this->Modified();
932 }
933 
934 //------------------------------------------------------------------------------
HasTranslucentPolygonalGeometry()935 bool vtkOpenGLPointGaussianMapper::HasTranslucentPolygonalGeometry()
936 {
937   // emissive always needs to be opaque
938   if (this->Emissive)
939   {
940     return false;
941   }
942   return this->Superclass::HasTranslucentPolygonalGeometry();
943 }
944 
945 //------------------------------------------------------------------------------
BuildScaleTable()946 void vtkOpenGLPointGaussianMapper::BuildScaleTable()
947 {
948   double range[2];
949 
950   // if a piecewise function was provided, use it to map the opacities
951   vtkPiecewiseFunction* pwf = this->GetScaleFunction();
952   int tableSize = this->GetScaleTableSize();
953 
954   delete[] this->ScaleTable;
955   this->ScaleTable = new float[tableSize + 1];
956   if (pwf)
957   {
958     // build the interpolation table
959     pwf->GetRange(range);
960     pwf->GetTable(range[0], range[1], tableSize, this->ScaleTable);
961     // duplicate the last value for bilinear interp edge case
962     this->ScaleTable[tableSize] = this->ScaleTable[tableSize - 1];
963     this->ScaleScale = (tableSize - 1.0) / (range[1] - range[0]);
964     this->ScaleOffset = range[0];
965   }
966   this->Modified();
967 }
968 
969 //------------------------------------------------------------------------------
BuildOpacityTable()970 void vtkOpenGLPointGaussianMapper::BuildOpacityTable()
971 {
972   double range[2];
973 
974   // if a piecewise function was provided, use it to map the opacities
975   vtkPiecewiseFunction* pwf = this->GetScalarOpacityFunction();
976   int tableSize = this->GetOpacityTableSize();
977 
978   delete[] this->OpacityTable;
979   this->OpacityTable = new float[tableSize + 1];
980   if (pwf)
981   {
982     // build the interpolation table
983     pwf->GetRange(range);
984     pwf->GetTable(range[0], range[1], tableSize, this->OpacityTable);
985     // duplicate the last value for bilinear interp edge case
986     this->OpacityTable[tableSize] = this->OpacityTable[tableSize - 1];
987     this->OpacityScale = (tableSize - 1.0) / (range[1] - range[0]);
988     this->OpacityOffset = range[0];
989   }
990   this->Modified();
991 }
992 
993 //------------------------------------------------------------------------------
FillInputPortInformation(int vtkNotUsed (port),vtkInformation * info)994 int vtkOpenGLPointGaussianMapper::FillInputPortInformation(
995   int vtkNotUsed(port), vtkInformation* info)
996 {
997   info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPolyData");
998   info->Append(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkCompositeDataSet");
999   return 1;
1000 }
1001 
1002 //------------------------------------------------------------------------------
CreateDefaultExecutive()1003 vtkExecutive* vtkOpenGLPointGaussianMapper::CreateDefaultExecutive()
1004 {
1005   return vtkCompositeDataPipeline::New();
1006 }
1007 
1008 //------------------------------------------------------------------------------
1009 // Looks at each DataSet and finds the union of all the bounds
ComputeBounds()1010 void vtkOpenGLPointGaussianMapper::ComputeBounds()
1011 {
1012   vtkCompositeDataSet* input = vtkCompositeDataSet::SafeDownCast(this->GetInputDataObject(0, 0));
1013 
1014   // If we don't have hierarchical data, test to see if we have
1015   // plain old polydata. In this case, the bounds are simply
1016   // the bounds of the input polydata.
1017   if (!input)
1018   {
1019     this->Superclass::ComputeBounds();
1020     return;
1021   }
1022 
1023   vtkBoundingBox bbox;
1024 
1025   // for each data set build a vtkPolyDataMapper
1026   vtkCompositeDataIterator* iter = input->NewIterator();
1027   iter->GoToFirstItem();
1028   while (!iter->IsDoneWithTraversal())
1029   {
1030     vtkPolyData* pd = vtkPolyData::SafeDownCast(iter->GetCurrentDataObject());
1031     if (pd)
1032     {
1033       double bounds[6];
1034       pd->GetCellsBounds(bounds);
1035       bbox.AddBounds(bounds);
1036     }
1037     iter->GoToNextItem();
1038   }
1039   iter->Delete();
1040 
1041   bbox.GetBounds(this->Bounds);
1042 }
1043 
1044 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)1045 void vtkOpenGLPointGaussianMapper::PrintSelf(ostream& os, vtkIndent indent)
1046 {
1047   this->Superclass::PrintSelf(os, indent);
1048 }
1049 
ProcessSelectorPixelBuffers(vtkHardwareSelector * sel,std::vector<unsigned int> & pixeloffsets,vtkProp * prop)1050 void vtkOpenGLPointGaussianMapper::ProcessSelectorPixelBuffers(
1051   vtkHardwareSelector* sel, std::vector<unsigned int>& pixeloffsets, vtkProp* prop)
1052 {
1053   if (sel->GetCurrentPass() == vtkHardwareSelector::ACTOR_PASS)
1054   {
1055     this->PickPixels.clear();
1056     return;
1057   }
1058 
1059   if (PickPixels.empty() && !pixeloffsets.empty())
1060   {
1061     // preprocess the image to find matching pixels and
1062     // store them in a map of vectors based on flat index
1063     // this makes the block processing far faster as we just
1064     // loop over the pixels for our block
1065     unsigned char* compositedata =
1066       sel->GetRawPixelBuffer(vtkHardwareSelector::COMPOSITE_INDEX_PASS);
1067 
1068     if (!compositedata)
1069     {
1070       return;
1071     }
1072 
1073     int maxFlatIndex = 0;
1074     for (auto hiter = this->Helpers.begin(); hiter != this->Helpers.end(); ++hiter)
1075     {
1076       maxFlatIndex = ((*hiter)->FlatIndex > maxFlatIndex) ? (*hiter)->FlatIndex : maxFlatIndex;
1077     }
1078 
1079     this->PickPixels.resize(maxFlatIndex + 1);
1080 
1081     for (auto pos : pixeloffsets)
1082     {
1083       int compval = compositedata[pos + 2];
1084       compval = compval << 8;
1085       compval |= compositedata[pos + 1];
1086       compval = compval << 8;
1087       compval |= compositedata[pos];
1088       compval -= 1;
1089       if (compval <= maxFlatIndex)
1090       {
1091         this->PickPixels[compval].push_back(pos);
1092       }
1093     }
1094   }
1095 
1096   // for each block update the image
1097   for (auto hiter = this->Helpers.begin(); hiter != this->Helpers.end(); ++hiter)
1098   {
1099     if (!this->PickPixels[(*hiter)->FlatIndex].empty())
1100     {
1101       (*hiter)->ProcessSelectorPixelBuffers(sel, this->PickPixels[(*hiter)->FlatIndex], prop);
1102     }
1103   }
1104 }
1105