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