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