1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkUnstructuredGridVolumeRayCastMapper.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 #include "vtkUnstructuredGridVolumeRayCastMapper.h"
16 
17 #include "vtkCamera.h"
18 #include "vtkEncodedGradientEstimator.h"
19 #include "vtkEncodedGradientShader.h"
20 #include "vtkFiniteDifferenceGradientEstimator.h"
21 #include "vtkUnstructuredGrid.h"
22 #include "vtkMath.h"
23 #include "vtkMultiThreader.h"
24 #include "vtkObjectFactory.h"
25 #include "vtkPlaneCollection.h"
26 #include "vtkPointData.h"
27 #include "vtkRenderWindow.h"
28 #include "vtkRenderer.h"
29 #include "vtkTimerLog.h"
30 #include "vtkTransform.h"
31 #include "vtkVolumeProperty.h"
32 #include "vtkUnstructuredGridBunykRayCastFunction.h"
33 #include "vtkUnstructuredGridVolumeRayCastIterator.h"
34 #include "vtkUnstructuredGridPreIntegration.h"
35 #include "vtkUnstructuredGridPartialPreIntegration.h"
36 #include "vtkUnstructuredGridHomogeneousRayIntegrator.h"
37 #include "vtkRayCastImageDisplayHelper.h"
38 #include "vtkDoubleArray.h"
39 #include "vtkIdList.h"
40 
41 #include <cmath>
42 
43 VTK_THREAD_RETURN_TYPE UnstructuredGridVolumeRayCastMapper_CastRays( void *arg );
44 
45 
46 vtkStandardNewMacro(vtkUnstructuredGridVolumeRayCastMapper);
47 
48 vtkCxxSetObjectMacro(vtkUnstructuredGridVolumeRayCastMapper, RayCastFunction,
49                      vtkUnstructuredGridVolumeRayCastFunction);
50 vtkCxxSetObjectMacro(vtkUnstructuredGridVolumeRayCastMapper, RayIntegrator,
51                      vtkUnstructuredGridVolumeRayIntegrator);
52 
53 // Construct a new vtkUnstructuredGridVolumeRayCastMapper with default values
vtkUnstructuredGridVolumeRayCastMapper()54 vtkUnstructuredGridVolumeRayCastMapper::vtkUnstructuredGridVolumeRayCastMapper()
55 {
56   this->ImageSampleDistance        =  1.0;
57   this->MinimumImageSampleDistance =  1.0;
58   this->MaximumImageSampleDistance = 10.0;
59   this->AutoAdjustSampleDistances  =  1;
60 
61   this->ImageMemorySize[0]     = 0;
62   this->ImageMemorySize[1]     = 0;
63 
64   this->Threader               = vtkMultiThreader::New();
65   this->NumberOfThreads        = this->Threader->GetNumberOfThreads();
66 
67   this->Image                  = nullptr;
68 
69   this->RenderTimeTable        = nullptr;
70   this->RenderVolumeTable      = nullptr;
71   this->RenderRendererTable    = nullptr;
72   this->RenderTableSize        = 0;
73   this->RenderTableEntries     = 0;
74 
75   this->ZBuffer                = nullptr;
76   this->ZBufferSize[0]         = 0;
77   this->ZBufferSize[1]         = 0;
78   this->ZBufferOrigin[0]       = 0;
79   this->ZBufferOrigin[1]       = 0;
80 
81   this->IntermixIntersectingGeometry = 1;
82 
83   this->ImageDisplayHelper     = vtkRayCastImageDisplayHelper::New();
84 
85   this->RayCastFunction = vtkUnstructuredGridBunykRayCastFunction::New();
86   this->RayIntegrator = nullptr;
87   this->RealRayIntegrator = nullptr;
88 }
89 
90 // Destruct a vtkUnstructuredGridVolumeRayCastMapper - clean up any memory used
~vtkUnstructuredGridVolumeRayCastMapper()91 vtkUnstructuredGridVolumeRayCastMapper::~vtkUnstructuredGridVolumeRayCastMapper()
92 {
93   this->Threader->Delete();
94 
95   delete [] this->Image;
96 
97   if ( this->RenderTableSize )
98   {
99     delete [] this->RenderTimeTable;
100     delete [] this->RenderVolumeTable;
101     delete [] this->RenderRendererTable;
102   }
103 
104   this->ImageDisplayHelper->Delete();
105 
106   this->SetRayCastFunction(nullptr);
107   this->SetRayIntegrator(nullptr);
108   if (this->RealRayIntegrator)
109   {
110     this->RealRayIntegrator->UnRegister(this);
111   }
112 }
113 
RetrieveRenderTime(vtkRenderer * ren,vtkVolume * vol)114 float vtkUnstructuredGridVolumeRayCastMapper::RetrieveRenderTime( vtkRenderer *ren,
115                                                                   vtkVolume   *vol )
116 {
117   int i;
118 
119   for ( i = 0; i < this->RenderTableEntries; i++ )
120   {
121     if ( this->RenderVolumeTable[i] == vol &&
122          this->RenderRendererTable[i] == ren )
123     {
124       return this->RenderTimeTable[i];
125     }
126   }
127 
128   return 0.0;
129 }
130 
StoreRenderTime(vtkRenderer * ren,vtkVolume * vol,float time)131 void vtkUnstructuredGridVolumeRayCastMapper::StoreRenderTime( vtkRenderer *ren,
132                                                               vtkVolume   *vol,
133                                                               float       time )
134 {
135   int i;
136   for ( i = 0; i < this->RenderTableEntries; i++ )
137   {
138     if ( this->RenderVolumeTable[i] == vol &&
139          this->RenderRendererTable[i] == ren )
140     {
141       this->RenderTimeTable[i] = time;
142       return;
143     }
144   }
145 
146 
147   // Need to increase size
148   if ( this->RenderTableEntries >= this->RenderTableSize )
149   {
150     if ( this->RenderTableSize == 0 )
151     {
152       this->RenderTableSize = 10;
153     }
154     else
155     {
156       this->RenderTableSize *= 2;
157     }
158 
159     float       *oldTimePtr     = this->RenderTimeTable;
160     vtkVolume   **oldVolumePtr   = this->RenderVolumeTable;
161     vtkRenderer **oldRendererPtr = this->RenderRendererTable;
162 
163     this->RenderTimeTable     = new float [this->RenderTableSize];
164     this->RenderVolumeTable   = new vtkVolume *[this->RenderTableSize];
165     this->RenderRendererTable = new vtkRenderer *[this->RenderTableSize];
166 
167     for (i = 0; i < this->RenderTableEntries; i++ )
168     {
169       this->RenderTimeTable[i] = oldTimePtr[i];
170       this->RenderVolumeTable[i] = oldVolumePtr[i];
171       this->RenderRendererTable[i] = oldRendererPtr[i];
172     }
173 
174     delete [] oldTimePtr;
175     delete [] oldVolumePtr;
176     delete [] oldRendererPtr;
177   }
178 
179   this->RenderTimeTable[this->RenderTableEntries] = time;
180   this->RenderVolumeTable[this->RenderTableEntries] = vol;
181   this->RenderRendererTable[this->RenderTableEntries] = ren;
182 
183   this->RenderTableEntries++;
184 }
185 
ReleaseGraphicsResources(vtkWindow *)186 void vtkUnstructuredGridVolumeRayCastMapper::ReleaseGraphicsResources(vtkWindow *)
187 {
188 }
189 
Render(vtkRenderer * ren,vtkVolume * vol)190 void vtkUnstructuredGridVolumeRayCastMapper::Render( vtkRenderer *ren, vtkVolume *vol )
191 {
192   int i;
193 
194   // Check for input
195   if ( this->GetInput() == nullptr )
196   {
197     vtkErrorMacro(<< "No Input!");
198     return;
199   }
200 
201   int inputAlgPort;
202   vtkAlgorithm* inputAlg = this->GetInputAlgorithm(0, 0, inputAlgPort);
203   inputAlg->UpdateWholeExtent();
204 
205   this->Scalars = this->GetScalars(this->GetInput(), this->ScalarMode,
206                                    this->ArrayAccessMode,
207                                    this->ArrayId, this->ArrayName,
208                                    this->CellScalars);
209 
210   if (this->Scalars == nullptr)
211   {
212     vtkErrorMacro("Can't use the ray cast mapper without scalars!");
213     return;
214   }
215 
216   // Check to make sure we have an appropriate integrator.
217   if (this->RayIntegrator)
218   {
219     if (this->RealRayIntegrator != this->RayIntegrator)
220     {
221       if (this->RealRayIntegrator)
222       {
223         this->RealRayIntegrator->UnRegister(this);
224       }
225       this->RealRayIntegrator = this->RayIntegrator;
226       this->RealRayIntegrator->Register(this);
227     }
228   }
229   else
230   {
231 
232 #define ESTABLISH_INTEGRATOR(classname)                                        \
233   if (   !this->RealRayIntegrator                                              \
234       || (!this->RealRayIntegrator->IsA(#classname)) )                         \
235   {                                                                          \
236     if (this->RealRayIntegrator) this->RealRayIntegrator->UnRegister(this);    \
237     this->RealRayIntegrator = classname::New();                                \
238     this->RealRayIntegrator->Register(this);                                   \
239     this->RealRayIntegrator->Delete();                                         \
240   }                                                                          \
241 
242     if (this->CellScalars)
243     {
244       ESTABLISH_INTEGRATOR(vtkUnstructuredGridHomogeneousRayIntegrator);
245     }
246     else
247     {
248       if (vol->GetProperty()->GetIndependentComponents())
249       {
250         ESTABLISH_INTEGRATOR(vtkUnstructuredGridPreIntegration);
251       }
252       else
253       {
254         ESTABLISH_INTEGRATOR(vtkUnstructuredGridPartialPreIntegration);
255       }
256     }
257   }
258 
259 #undef ESTABLISH_INTEGRATOR
260 
261   // Start timing now. We didn't want to capture the update of the
262   // input data in the times
263   this->Timer->StartTimer();
264 
265   int oldImageMemorySize[2];
266   oldImageMemorySize[0] = this->ImageMemorySize[0];
267   oldImageMemorySize[1] = this->ImageMemorySize[1];
268 
269   // If we are automatically adjusting the size to achieve a desired frame
270   // rate, then do that adjustment here. Base the new image sample distance
271   // on the previous one and the previous render time. Don't let
272   // the adjusted image sample distance be less than the minimum image sample
273   // distance or more than the maximum image sample distance.
274   float oldImageSampleDistance = this->ImageSampleDistance;
275   if ( this->AutoAdjustSampleDistances )
276   {
277     float oldTime = this->RetrieveRenderTime( ren, vol );
278     float newTime = vol->GetAllocatedRenderTime();
279     this->ImageSampleDistance *= sqrt(oldTime / newTime);
280     this->ImageSampleDistance =
281       (this->ImageSampleDistance>this->MaximumImageSampleDistance)?
282       (this->MaximumImageSampleDistance):(this->ImageSampleDistance);
283     this->ImageSampleDistance =
284       (this->ImageSampleDistance<this->MinimumImageSampleDistance)?
285       (this->MinimumImageSampleDistance):(this->ImageSampleDistance);
286   }
287 
288   // The full image fills the viewport. First, compute the actual viewport
289   // size, then divide by the ImageSampleDistance to find the full image
290   // size in pixels
291   int width, height;
292   ren->GetTiledSize(&width, &height);
293   this->ImageViewportSize[0] =
294     static_cast<int>(width/this->ImageSampleDistance);
295   this->ImageViewportSize[1] =
296     static_cast<int>(height/this->ImageSampleDistance);
297 
298   this->ImageInUseSize[0] = this->ImageViewportSize[0];
299   this->ImageInUseSize[1] = this->ImageViewportSize[1];
300   this->ImageOrigin[0] = 0;
301   this->ImageOrigin[1] = 0;
302 
303   // What is a power of 2 size big enough to fit this image?
304   this->ImageMemorySize[0] = 32;
305   this->ImageMemorySize[1] = 32;
306   while ( this->ImageMemorySize[0] < this->ImageInUseSize[0] )
307   {
308     this->ImageMemorySize[0] *= 2;
309   }
310   while ( this->ImageMemorySize[1] < this->ImageInUseSize[1] )
311   {
312     this->ImageMemorySize[1] *= 2;
313   }
314 
315   // If the old image size is much too big (more than twice in
316   // either direction) then set the old width to 0 which will
317   // cause the image to be recreated
318   if ( oldImageMemorySize[0] > 2*this->ImageMemorySize[0] ||
319        oldImageMemorySize[1] > 2*this->ImageMemorySize[1] )
320   {
321     oldImageMemorySize[0] = 0;
322   }
323 
324   // If the old image is big enough (but not too big - we handled
325   // that above) then we'll bump up our required size to the
326   // previous one. This will keep us from thrashing.
327   if ( oldImageMemorySize[0] >= this->ImageMemorySize[0] &&
328        oldImageMemorySize[1] >= this->ImageMemorySize[1] )
329   {
330     this->ImageMemorySize[0] = oldImageMemorySize[0];
331     this->ImageMemorySize[1] = oldImageMemorySize[1];
332   }
333 
334   // Do we already have a texture big enough? If not, create a new one and
335   // clear it.
336   if ( !this->Image ||
337        this->ImageMemorySize[0] > oldImageMemorySize[0] ||
338        this->ImageMemorySize[1] > oldImageMemorySize[1] )
339   {
340     // If there is an image there must be row bounds
341     delete [] this->Image;
342 
343     this->Image = new unsigned char[(this->ImageMemorySize[0] *
344                                      this->ImageMemorySize[1] * 4)];
345 
346     unsigned char *ucptr = this->Image;
347 
348     for ( i = 0; i < this->ImageMemorySize[0]*this->ImageMemorySize[1]; i++ )
349     {
350       *(ucptr++) = 0;
351       *(ucptr++) = 0;
352       *(ucptr++) = 0;
353       *(ucptr++) = 0;
354     }
355   }
356 
357   // Capture the zbuffer if necessary
358   if ( this->IntermixIntersectingGeometry &&
359        ren->GetNumberOfPropsRendered() )
360   {
361     int x1, x2, y1, y2;
362     double *viewport   =  ren->GetViewport();
363     int *renWinSize   =  ren->GetRenderWindow()->GetSize();
364 
365     // turn this->ImageOrigin into (x1,y1) in window (not viewport!)
366     // coordinates.
367     x1 = static_cast<int> (
368       viewport[0] * static_cast<float>(renWinSize[0]) +
369       static_cast<float>(this->ImageOrigin[0]) * this->ImageSampleDistance );
370     y1 = static_cast<int> (
371       viewport[1] * static_cast<float>(renWinSize[1]) +
372       static_cast<float>(this->ImageOrigin[1]) * this->ImageSampleDistance);
373 
374     // compute z buffer size
375     this->ZBufferSize[0] = static_cast<int>(
376       static_cast<float>(this->ImageInUseSize[0]) * this->ImageSampleDistance);
377     this->ZBufferSize[1] = static_cast<int>(
378       static_cast<float>(this->ImageInUseSize[1]) * this->ImageSampleDistance);
379 
380     // Use the size to compute (x2,y2) in window coordinates
381     x2 = x1 + this->ZBufferSize[0] - 1;
382     y2 = y1 + this->ZBufferSize[1] - 1;
383 
384     // This is the z buffer origin (in viewport coordinates)
385     this->ZBufferOrigin[0] = static_cast<int>(
386       static_cast<float>(this->ImageOrigin[0]) * this->ImageSampleDistance);
387     this->ZBufferOrigin[1] = static_cast<int>(
388       static_cast<float>(this->ImageOrigin[1]) * this->ImageSampleDistance);
389 
390     // Capture the z buffer
391     this->ZBuffer = ren->GetRenderWindow()->GetZbufferData(x1,y1,x2,y2);
392   }
393 
394   this->RayCastFunction->Initialize( ren, vol );
395 
396   this->RealRayIntegrator->Initialize(vol, this->Scalars);
397 
398   // Save the volume and mapper temporarily so that they can be accessed later
399   this->CurrentVolume   = vol;
400   this->CurrentRenderer = ren;
401 
402   // Create iterators and buffers here to prevent race conditions.
403   this->RayCastIterators
404     = new vtkUnstructuredGridVolumeRayCastIterator*[this->NumberOfThreads];
405   this->IntersectedCellsBuffer    = new vtkIdList*[this->NumberOfThreads];
406   this->IntersectionLengthsBuffer = new vtkDoubleArray*[this->NumberOfThreads];
407   this->NearIntersectionsBuffer   = new vtkDataArray*[this->NumberOfThreads];
408   this->FarIntersectionsBuffer    = new vtkDataArray*[this->NumberOfThreads];
409   for (i = 0; i < this->NumberOfThreads; i++)
410   {
411     this->RayCastIterators[i] = this->RayCastFunction->NewIterator();
412     this->IntersectionLengthsBuffer[i] = vtkDoubleArray::New();
413     this->IntersectionLengthsBuffer[i]
414       ->Allocate(this->RayCastIterators[i]->GetMaxNumberOfIntersections());
415     this->NearIntersectionsBuffer[i]
416       = vtkDataArray::CreateDataArray(this->Scalars->GetDataType());
417     this->NearIntersectionsBuffer[i]
418       ->Allocate(this->RayCastIterators[i]->GetMaxNumberOfIntersections());
419     if (this->CellScalars)
420     {
421       this->IntersectedCellsBuffer[i] = vtkIdList::New();
422       this->IntersectedCellsBuffer[i]
423         ->Allocate(this->RayCastIterators[i]->GetMaxNumberOfIntersections());
424       this->FarIntersectionsBuffer[i] = this->NearIntersectionsBuffer[i];
425     }
426     else
427     {
428       this->IntersectedCellsBuffer[i] = nullptr;
429       this->FarIntersectionsBuffer[i]
430         = vtkDataArray::CreateDataArray(this->Scalars->GetDataType());
431       this->FarIntersectionsBuffer[i]
432         ->Allocate(this->RayCastIterators[i]->GetMaxNumberOfIntersections());
433     }
434   }
435 
436   // Set the number of threads to use for ray casting,
437   // then set the execution method and do it.
438   this->Threader->SetNumberOfThreads( this->NumberOfThreads );
439   this->Threader->SetSingleMethod( UnstructuredGridVolumeRayCastMapper_CastRays,
440                                    (void *)this);
441   this->Threader->SingleMethodExecute();
442 
443   // We don't need these anymore
444   this->CurrentVolume   = nullptr;
445   this->CurrentRenderer = nullptr;
446   for (i = 0; i < this->NumberOfThreads; i++)
447   {
448     this->RayCastIterators[i]->Delete();
449     this->IntersectionLengthsBuffer[i]->Delete();
450     this->NearIntersectionsBuffer[i]->Delete();
451     if (this->CellScalars)
452     {
453       this->IntersectedCellsBuffer[i]->Delete();
454     }
455     else
456     {
457       this->FarIntersectionsBuffer[i]->Delete();
458     }
459   }
460   delete[] this->RayCastIterators;
461   delete[] this->IntersectedCellsBuffer;
462   delete[] this->IntersectionLengthsBuffer;
463   delete[] this->NearIntersectionsBuffer;
464   delete[] this->FarIntersectionsBuffer;
465 
466   if ( !ren->GetRenderWindow()->GetAbortRender() )
467   {
468     float depth;
469     if ( this->IntermixIntersectingGeometry )
470     {
471       depth = this->GetMinimumBoundsDepth( ren, vol );
472     }
473     else
474     {
475       depth = -1;
476     }
477 
478     this->ImageDisplayHelper->
479       RenderTexture( vol, ren,
480                      this->ImageMemorySize,
481                      this->ImageViewportSize,
482                      this->ImageInUseSize,
483                      this->ImageOrigin,
484                      depth,
485                      this->Image );
486 
487     this->Timer->StopTimer();
488     this->TimeToDraw = this->Timer->GetElapsedTime();
489     this->StoreRenderTime( ren, vol, this->TimeToDraw );
490   }
491   else
492   {
493     this->ImageSampleDistance = oldImageSampleDistance;
494   }
495 
496 
497   delete [] this->ZBuffer;
498   this->ZBuffer = nullptr;
499 
500   this->UpdateProgress(1.0);
501 }
502 
UnstructuredGridVolumeRayCastMapper_CastRays(void * arg)503 VTK_THREAD_RETURN_TYPE UnstructuredGridVolumeRayCastMapper_CastRays( void *arg )
504 {
505   // Get the info out of the input structure
506   int threadID    = ((vtkMultiThreader::ThreadInfo *)(arg))->ThreadID;
507   int threadCount = ((vtkMultiThreader::ThreadInfo *)(arg))->NumberOfThreads;
508   vtkUnstructuredGridVolumeRayCastMapper *me =
509     (vtkUnstructuredGridVolumeRayCastMapper *)((vtkMultiThreader::ThreadInfo *)arg)->UserData;
510 
511   if ( !me )
512   {
513     vtkGenericWarningMacro("The volume does not have a ray cast mapper!");
514     return VTK_THREAD_RETURN_VALUE;
515   }
516 
517   me->CastRays( threadID, threadCount );
518 
519   return VTK_THREAD_RETURN_VALUE;
520 }
521 
522 template<class T>
vtkUGVRCMLookupCopy(const T * src,T * dest,vtkIdType * lookup,int numcomponents,int numtuples)523 inline void vtkUGVRCMLookupCopy(const T *src, T *dest, vtkIdType *lookup,
524                                 int numcomponents, int numtuples)
525 {
526   for (vtkIdType i = 0; i < numtuples; i++)
527   {
528     const T *srctuple = src + lookup[i] * numcomponents;
529     for (int j = 0; j < numcomponents; j++)
530     {
531       *dest = *srctuple;
532       dest++;  srctuple++;
533     }
534   }
535 }
536 
CastRays(int threadID,int threadCount)537 void vtkUnstructuredGridVolumeRayCastMapper::CastRays( int threadID, int threadCount )
538 {
539   int i, j;
540   unsigned char *ucptr;
541 
542   vtkRenderWindow *renWin = this->CurrentRenderer->GetRenderWindow();
543   vtkUnstructuredGridVolumeRayCastIterator *iterator
544     = this->RayCastIterators[threadID];
545 
546   vtkIdList *intersectedCells = this->IntersectedCellsBuffer[threadID];
547   vtkDoubleArray *intersectionLengths=this->IntersectionLengthsBuffer[threadID];
548   vtkDataArray *nearIntersections = this->NearIntersectionsBuffer[threadID];
549   vtkDataArray *farIntersections = this->FarIntersectionsBuffer[threadID];
550 
551   for ( j = 0; j < this->ImageInUseSize[1]; j++ )
552   {
553     if ( j%threadCount != threadID )
554     {
555       continue;
556     }
557 
558     if ( !threadID )
559     {
560       this->UpdateProgress((double)j/this->ImageInUseSize[1]);
561       if ( renWin->CheckAbortStatus() )
562       {
563         break;
564       }
565     }
566     else if ( renWin->GetAbortRender() )
567     {
568       break;
569     }
570 
571     ucptr = this->Image + 4*j*this->ImageMemorySize[0];
572 
573     for ( i = 0; i < this->ImageInUseSize[0]; i++ )
574     {
575       int x = i + this->ImageOrigin[0];
576       int y = j + this->ImageOrigin[1];
577 
578       double bounds[2] = {0.0,1.0};
579       float color[4] = {0.0f, 0.0f, 0.0f, 0.0f};
580 
581       if ( this->ZBuffer )
582       {
583         bounds[1] = this->GetZBufferValue( x, y );
584       }
585 
586       iterator->SetBounds(bounds);
587       iterator->Initialize(x, y);
588 
589       vtkIdType numIntersections;
590       do
591       {
592         if (this->CellScalars)
593         {
594           numIntersections = iterator->GetNextIntersections(intersectedCells,
595                                                             intersectionLengths,
596                                                             nullptr,
597                                                             nullptr, nullptr);
598           nearIntersections
599             ->SetNumberOfComponents(this->Scalars->GetNumberOfComponents());
600           nearIntersections->SetNumberOfTuples(numIntersections);
601           switch (this->Scalars->GetDataType())
602           {
603             vtkTemplateMacro(vtkUGVRCMLookupCopy
604                              ((const VTK_TT*)this->Scalars->GetVoidPointer(0),
605                               (VTK_TT*)nearIntersections->GetVoidPointer(0),
606                               intersectedCells->GetPointer(0),
607                               this->Scalars->GetNumberOfComponents(),
608                               numIntersections));
609           }
610         }
611         else
612         {
613           numIntersections = iterator->GetNextIntersections(nullptr,
614                                                             intersectionLengths,
615                                                             this->Scalars,
616                                                             nearIntersections,
617                                                             farIntersections);
618         }
619         if (numIntersections < 1) break;
620         this->RealRayIntegrator->Integrate(intersectionLengths,
621                                            nearIntersections,
622                                            farIntersections,
623                                            color);
624       } while (color[3] < 0.99);
625 
626       if ( color[3] > 0.0 )
627       {
628         int val;
629         val = static_cast<int>(color[0]*255.0);
630         val = (val > 255)?(255):(val);
631         val = (val <   0)?(  0):(val);
632         ucptr[0] = static_cast<unsigned char>(val);
633 
634         val = static_cast<int>(color[1]*255.0);
635         val = (val > 255)?(255):(val);
636         val = (val <   0)?(  0):(val);
637         ucptr[1] = static_cast<unsigned char>(val);
638 
639         val = static_cast<int>(color[2]*255.0);
640         val = (val > 255)?(255):(val);
641         val = (val <   0)?(  0):(val);
642         ucptr[2] = static_cast<unsigned char>(val);
643 
644         val = static_cast<int>(color[3]*255.0);
645         val = (val > 255)?(255):(val);
646         val = (val <   0)?(  0):(val);
647         ucptr[3] = static_cast<unsigned char>(val);
648       }
649       else
650       {
651         ucptr[0] = 0;
652         ucptr[1] = 0;
653         ucptr[2] = 0;
654         ucptr[3] = 0;
655       }
656       ucptr+=4;
657     }
658   }
659 }
660 
661 double vtkUnstructuredGridVolumeRayCastMapper::
GetMinimumBoundsDepth(vtkRenderer * ren,vtkVolume * vol)662 GetMinimumBoundsDepth( vtkRenderer *ren, vtkVolume   *vol )
663 {
664   double bounds[6];
665   vol->GetBounds( bounds );
666 
667   vtkTransform *perspectiveTransform = vtkTransform::New();
668   vtkMatrix4x4 *perspectiveMatrix = vtkMatrix4x4::New();
669 
670   ren->ComputeAspect();
671   double *aspect = ren->GetAspect();
672 
673   // Get the view matrix in two steps - there is a one step method in camera
674   // but it turns off stereo so we do not want to use that one
675   vtkCamera *cam = ren->GetActiveCamera();
676   perspectiveTransform->Identity();
677   perspectiveTransform->Concatenate(
678     cam->GetProjectionTransformMatrix(aspect[0]/aspect[1], 0.0, 1.0 ));
679   perspectiveTransform->Concatenate(cam->GetViewTransformMatrix());
680   perspectiveMatrix->DeepCopy(perspectiveTransform->GetMatrix());
681 
682   double minZ = 1.0;
683 
684   for ( int k = 0; k < 2; k++ )
685   {
686     for ( int j = 0; j < 2; j++ )
687     {
688       for ( int i = 0; i < 2; i++ )
689       {
690         double inPoint[4];
691         inPoint[0] = bounds[  i];
692         inPoint[1] = bounds[2+j];
693         inPoint[2] = bounds[4+k];
694         inPoint[3] = 1.0;
695 
696         double outPoint[4];
697         perspectiveMatrix->MultiplyPoint( inPoint, outPoint );
698         double testZ = outPoint[2] / outPoint[3];
699         minZ = ( testZ < minZ ) ? (testZ) : (minZ);
700       }
701     }
702   }
703 
704   perspectiveTransform->Delete();
705   perspectiveMatrix->Delete();
706 
707   return minZ;
708 }
709 
GetZBufferValue(int x,int y)710 double vtkUnstructuredGridVolumeRayCastMapper::GetZBufferValue(int x, int y)
711 {
712   int xPos, yPos;
713 
714   xPos = static_cast<int>(static_cast<float>(x) * this->ImageSampleDistance);
715   yPos = static_cast<int>(static_cast<float>(y) * this->ImageSampleDistance);
716 
717   xPos = (xPos >= this->ZBufferSize[0])?(this->ZBufferSize[0]-1):(xPos);
718   yPos = (yPos >= this->ZBufferSize[1])?(this->ZBufferSize[1]-1):(yPos);
719 
720   return *(this->ZBuffer + yPos*this->ZBufferSize[0] + xPos);
721 }
722 
723 // Print method for vtkUnstructuredGridVolumeRayCastMapper
PrintSelf(ostream & os,vtkIndent indent)724 void vtkUnstructuredGridVolumeRayCastMapper::PrintSelf(ostream& os, vtkIndent indent)
725 {
726   this->Superclass::PrintSelf(os,indent);
727 
728   os << indent << "Image Sample Distance: "
729      << this->ImageSampleDistance << "\n";
730   os << indent << "Minimum Image Sample Distance: "
731      << this->MinimumImageSampleDistance << "\n";
732   os << indent << "Maximum Image Sample Distance: "
733      << this->MaximumImageSampleDistance << "\n";
734   os << indent << "Auto Adjust Sample Distances: "
735      << this->AutoAdjustSampleDistances << "\n";
736   os << indent << "Intermix Intersecting Geometry: "
737     << (this->IntermixIntersectingGeometry ? "On\n" : "Off\n");
738 
739   os << indent << "Number Of Threads: " << this->NumberOfThreads << "\n";
740 
741   if (this->RayCastFunction)
742   {
743     os << indent << "RayCastFunction: " <<
744       this->RayCastFunction->GetClassName() << "\n";
745   }
746   else
747   {
748     os << indent << "RayCastFunction: (none)\n";
749   }
750 
751   if (this->RayIntegrator)
752   {
753     os << indent << "RayIntegrator: "
754        << this->RayIntegrator->GetClassName() << endl;
755   }
756   else
757   {
758     os << indent << "RayIntegrator: (automatic)" << endl;
759   }
760 
761   // Do not want to print this->ImageOrigin, this->ImageViewportSize or
762   // this->ImageInUseSize since these are just internal variables with Get
763   // methods for access from the ray cast function (not part of the public
764   // API)
765 }
766 
767