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