1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkGPUVolumeRayCastMapper.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 "vtkGPUVolumeRayCastMapper.h"
16 
17 #include "vtkObjectFactory.h"
18 #include "vtkImageData.h"
19 #include "vtkPointData.h"
20 #include "vtkCellData.h"
21 #include "vtkDataArray.h"
22 #include "vtkTimerLog.h"
23 #include "vtkImageResample.h"
24 #include "vtkVolume.h"
25 #include "vtkVolumeProperty.h"
26 #include "vtkRenderer.h"
27 #include "vtkRenderWindow.h"
28 #include <cassert>
29 #include "vtkCommand.h" // for VolumeMapperRender{Start|End|Progress}Event
30 #include "vtkCamera.h"
31 #include "vtkRendererCollection.h"
32 #include "vtkMultiThreader.h"
33 #include "vtkGPUInfoList.h"
34 #include "vtkGPUInfo.h"
35 
36 // Return NULL if no override is supplied.
37 vtkAbstractObjectFactoryNewMacro(vtkGPUVolumeRayCastMapper)
38 vtkCxxSetObjectMacro(vtkGPUVolumeRayCastMapper, MaskInput, vtkImageData);
39 vtkCxxSetObjectMacro(vtkGPUVolumeRayCastMapper, TransformedInput, vtkImageData);
40 
vtkGPUVolumeRayCastMapper()41 vtkGPUVolumeRayCastMapper::vtkGPUVolumeRayCastMapper()
42 {
43   this->AutoAdjustSampleDistances  = 1;
44   this->ImageSampleDistance        = 1.0;
45   this->MinimumImageSampleDistance = 1.0;
46   this->MaximumImageSampleDistance = 10.0;
47   this->SampleDistance             = 1.0;
48   this->SmallVolumeRender          = 0;
49   this->BigTimeToDraw              = 0.0;
50   this->SmallTimeToDraw            = 0.0;
51   this->FinalColorWindow           = 1.0;
52   this->FinalColorLevel            = 0.5;
53   this->GeneratingCanonicalView    = 0;
54   this->CanonicalViewImageData     = NULL;
55 
56   this->MaskInput                  = NULL;
57   this->MaskBlendFactor            = 1.0f;
58   this->MaskType
59     = vtkGPUVolumeRayCastMapper::LabelMapMaskType;
60 
61   this->AMRMode=0;
62   this->ClippedCroppingRegionPlanes[0]=VTK_DOUBLE_MAX;
63   this->ClippedCroppingRegionPlanes[1]=VTK_DOUBLE_MIN;
64   this->ClippedCroppingRegionPlanes[2]=VTK_DOUBLE_MAX;
65   this->ClippedCroppingRegionPlanes[3]=VTK_DOUBLE_MIN;
66   this->ClippedCroppingRegionPlanes[4]=VTK_DOUBLE_MAX;
67   this->ClippedCroppingRegionPlanes[5]=VTK_DOUBLE_MIN;
68 
69   this->MaxMemoryInBytes=0;
70   vtkGPUInfoList *l=vtkGPUInfoList::New();
71   l->Probe();
72   if(l->GetNumberOfGPUs()>0)
73     {
74     vtkGPUInfo *info=l->GetGPUInfo(0);
75     this->MaxMemoryInBytes=info->GetDedicatedVideoMemory();
76     if(this->MaxMemoryInBytes==0)
77       {
78       this->MaxMemoryInBytes=info->GetDedicatedSystemMemory();
79       }
80     // we ignore info->GetSharedSystemMemory(); as this is very slow.
81     }
82   l->Delete();
83 
84   if(this->MaxMemoryInBytes==0) // use some default value: 128MB.
85     {
86     this->MaxMemoryInBytes=128*1024*1024;
87     }
88 
89   this->MaxMemoryFraction = 0.75;
90 
91   this->ReportProgress=true;
92 
93   this->TransformedInput = NULL;
94   this->LastInput = NULL;
95 }
96 
97 // ----------------------------------------------------------------------------
~vtkGPUVolumeRayCastMapper()98 vtkGPUVolumeRayCastMapper::~vtkGPUVolumeRayCastMapper()
99 {
100   this->SetMaskInput(NULL);
101   this->SetTransformedInput(NULL);
102   this->LastInput = NULL;
103 }
104 
105 // ----------------------------------------------------------------------------
106 // The render method that is called from the volume. If this is a canonical
107 // view render, a specialized version of this method will be called instead.
108 // Otherwise we will
109 //   - Invoke a start event
110 //   - Start timing
111 //   - Check that everything is OK for rendering
112 //   - Render
113 //   - Stop the timer and record results
114 //   - Invoke an end event
115 // ----------------------------------------------------------------------------
Render(vtkRenderer * ren,vtkVolume * vol)116 void vtkGPUVolumeRayCastMapper::Render( vtkRenderer *ren, vtkVolume *vol )
117 {
118   // Catch renders that are happening due to a canonical view render and
119   // handle them separately.
120   if (this->GeneratingCanonicalView )
121     {
122     this->CanonicalViewRender(ren, vol);
123     return;
124     }
125 
126   // Invoke a VolumeMapperRenderStartEvent
127   this->InvokeEvent(vtkCommand::VolumeMapperRenderStartEvent,0);
128 
129   // Start the timer to time the length of this render
130   vtkTimerLog *timer = vtkTimerLog::New();
131   timer->StartTimer();
132 
133   // Make sure everything about this render is OK.
134   // This is where the input is updated.
135   if ( this->ValidateRender(ren, vol ) )
136     {
137     // Everything is OK - so go ahead and really do the render
138     this->GPURender( ren, vol);
139     }
140 
141   // Stop the timer
142   timer->StopTimer();
143   double t = timer->GetElapsedTime();
144 
145 //  cout << "Render Timer " << t << " seconds, " << 1.0/t << " frames per second" << endl;
146 
147   this->TimeToDraw = t;
148   timer->Delete();
149 
150   if ( vol->GetAllocatedRenderTime() < 1.0 )
151     {
152     this->SmallTimeToDraw = t;
153     }
154   else
155     {
156     this->BigTimeToDraw = t;
157     }
158 
159   // Invoke a VolumeMapperRenderEndEvent
160   this->InvokeEvent(vtkCommand::VolumeMapperRenderEndEvent,0);
161 }
162 
163 // ----------------------------------------------------------------------------
164 // Special version for rendering a canonical view - we don't do things like
165 // invoke start or end events, and we don't capture the render time.
166 // ----------------------------------------------------------------------------
CanonicalViewRender(vtkRenderer * ren,vtkVolume * vol)167 void vtkGPUVolumeRayCastMapper::CanonicalViewRender(vtkRenderer *ren,
168                                                     vtkVolume *vol )
169 {
170   // Make sure everything about this render is OK
171   if ( this->ValidateRender(ren, vol ) )
172     {
173     // Everything is OK - so go ahead and really do the render
174     this->GPURender( ren, vol);
175     }
176 }
177 
178 // ----------------------------------------------------------------------------
179 // This method us used by the render method to validate everything before
180 // attempting to render. This method returns 0 if something is not right -
181 // such as missing input, a null renderer or a null volume, no scalars, etc.
182 // In some cases it will produce a vtkErrorMacro message, and in others
183 // (for example, in the case of cropping planes that define a region with
184 // a volume or 0 or less) it will fail silently. If everything is OK, it will
185 // return with a value of 1.
186 // ----------------------------------------------------------------------------
ValidateRender(vtkRenderer * ren,vtkVolume * vol)187 int vtkGPUVolumeRayCastMapper::ValidateRender(vtkRenderer *ren,
188                                               vtkVolume *vol)
189 {
190   // Check that we have everything we need to render.
191   int goodSoFar = 1;
192 
193   // Check for a renderer - we MUST have one
194   if ( !ren )
195     {
196     goodSoFar = 0;
197     vtkErrorMacro("Renderer cannot be null.");
198     }
199 
200   // Check for the volume - we MUST have one
201   if ( goodSoFar && !vol )
202     {
203     goodSoFar = 0;
204     vtkErrorMacro("Volume cannot be null.");
205     }
206 
207   // Don't need to check if we have a volume property
208   // since the volume will create one if we don't. Also
209   // don't need to check for the scalar opacity function
210   // or the RGB transfer function since the property will
211   // create them if they do not yet exist.
212 
213   // However we must currently check that the number of
214   // color channels is 3
215   // TODO: lift this restriction - should work with
216   // gray functions as well. Right now turning off test
217   // because otherwise 4 component rendering isn't working.
218   // Will revisit.
219   if ( goodSoFar && vol->GetProperty()->GetColorChannels() != 3 )
220     {
221 //    goodSoFar = 0;
222 //    vtkErrorMacro("Must have a color transfer function.");
223     }
224 
225   // Check the cropping planes. If they are invalid, just silently
226   // fail. This will happen when an interactive widget is dragged
227   // such that it defines 0 or negative volume - this can happen
228   // and should just not render the volume.
229   // Check the cropping planes
230   if( goodSoFar && this->Cropping &&
231      (this->CroppingRegionPlanes[0]>=this->CroppingRegionPlanes[1] ||
232       this->CroppingRegionPlanes[2]>=this->CroppingRegionPlanes[3] ||
233       this->CroppingRegionPlanes[4]>=this->CroppingRegionPlanes[5] ))
234     {
235     // No error message here - we want to be silent
236     goodSoFar = 0;
237     }
238 
239   // Check that we have input data
240   vtkImageData *input=this->GetInput();
241 
242   if(goodSoFar && input==0)
243     {
244     vtkErrorMacro("Input is NULL but is required");
245     goodSoFar = 0;
246     }
247 
248   if(goodSoFar)
249     {
250     this->GetInputAlgorithm()->Update();
251     }
252 
253   // If we have a timestamp change or data change then create a new clone.
254   if(goodSoFar && (input != this->LastInput ||
255                    input->GetMTime() > this->TransformedInput->GetMTime()))
256     {
257     this->LastInput = input;
258 
259     vtkImageData* clone;
260     if(!this->TransformedInput)
261       {
262       clone = vtkImageData::New();
263       this->SetTransformedInput(clone);
264       clone->Delete();
265       }
266     else
267       {
268       clone = this->TransformedInput;
269       }
270 
271     clone->ShallowCopy(input);
272 
273     // @TODO: This is the workaround to deal with GPUVolumeRayCastMapper
274     // not able to handle extents starting from non zero values.
275     // There is not a easy fix in the GPU volume ray cast mapper hence
276     // this fix has been introduced.
277 
278     // Get the current extents.
279     int extents[6], real_extents[6];
280     clone->GetExtent(extents);
281     clone->GetExtent(real_extents);
282 
283     // Get the current origin and spacing.
284     double origin[3], spacing[3];
285     clone->GetOrigin(origin);
286     clone->GetSpacing(spacing);
287 
288     for (int cc=0; cc < 3; cc++)
289       {
290       // Transform the origin and the extents.
291       origin[cc] = origin[cc] + extents[2*cc]*spacing[cc];
292       extents[2*cc+1] -= extents[2*cc];
293       extents[2*cc] -= extents[2*cc];
294       }
295 
296     clone->SetOrigin(origin);
297     clone->SetExtent(extents);
298     }
299 
300   // Update the date then make sure we have scalars. Note
301   // that we must have point or cell scalars because field
302   // scalars are not supported.
303   vtkDataArray *scalars = NULL;
304   if ( goodSoFar )
305     {
306     // Now make sure we can find scalars
307     scalars=this->GetScalars(this->TransformedInput,this->ScalarMode,
308                              this->ArrayAccessMode,
309                              this->ArrayId,
310                              this->ArrayName,
311                              this->CellFlag);
312 
313     // We couldn't find scalars
314     if ( !scalars )
315       {
316       vtkErrorMacro("No scalars found on input.");
317       goodSoFar = 0;
318       }
319     // Even if we found scalars, if they are field data scalars that isn't good
320     else if ( this->CellFlag == 2 )
321       {
322       vtkErrorMacro("Only point or cell scalar support - found field scalars instead.");
323       goodSoFar = 0;
324       }
325     }
326 
327   // Make sure the scalar type is actually supported. This mappers supports
328   // almost all standard scalar types.
329   if ( goodSoFar )
330     {
331     switch(scalars->GetDataType())
332       {
333       case VTK_CHAR:
334         vtkErrorMacro(<< "scalar of type VTK_CHAR is not supported "
335                       << "because this type is platform dependent. "
336                       << "Use VTK_SIGNED_CHAR or VTK_UNSIGNED_CHAR instead.");
337         goodSoFar = 0;
338         break;
339       case VTK_BIT:
340         vtkErrorMacro("scalar of type VTK_BIT is not supported by this mapper.");
341         goodSoFar = 0;
342         break;
343       case VTK_ID_TYPE:
344         vtkErrorMacro("scalar of type VTK_ID_TYPE is not supported by this mapper.");
345         goodSoFar = 0;
346         break;
347       case VTK_STRING:
348         vtkErrorMacro("scalar of type VTK_STRING is not supported by this mapper.");
349         goodSoFar = 0;
350         break;
351       default:
352         // Don't need to do anything here
353         break;
354       }
355     }
356 
357   // Check on the blending type - we support composite and min / max intensity
358   if ( goodSoFar )
359     {
360     if(this->BlendMode!=vtkVolumeMapper::COMPOSITE_BLEND &&
361        this->BlendMode!=vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND &&
362        this->BlendMode!=vtkVolumeMapper::MINIMUM_INTENSITY_BLEND &&
363        this->BlendMode!=vtkVolumeMapper::ADDITIVE_BLEND)
364       {
365       goodSoFar = 0;
366       vtkErrorMacro(<< "Selected blend mode not supported. "
367                     << "Only Composite, MIP, MinIP and additive modes "
368                     << "are supported by the current implementation.");
369       }
370     }
371 
372   // This mapper supports 1 component data, or 4 component if it is not independent
373   // component (i.e. the four components define RGBA)
374   int numberOfComponents = 0;
375   if ( goodSoFar )
376     {
377     numberOfComponents = scalars->GetNumberOfComponents();
378     if( !(numberOfComponents == 1 ||
379           numberOfComponents == 4) )
380       {
381       goodSoFar = 0;
382       vtkErrorMacro(<< "Only one component scalars, or four "
383                     << "component with non-independent components, "
384                     << "are supported by this mapper.");
385       }
386     }
387 
388   // If this is four component data, then it better be unsigned char (RGBA).
389   if( goodSoFar &&
390       numberOfComponents == 4 &&
391       scalars->GetDataType() != VTK_UNSIGNED_CHAR)
392     {
393     goodSoFar = 0;
394     vtkErrorMacro("Only unsigned char is supported for 4-component scalars!");
395     }
396 
397   if(goodSoFar && numberOfComponents!=1 &&
398      this->BlendMode==vtkVolumeMapper::ADDITIVE_BLEND)
399     {
400     goodSoFar=0;
401     vtkErrorMacro("Additive mode only works with 1-component scalars!");
402     }
403 
404   // return our status
405   return goodSoFar;
406 }
407 
408 // ----------------------------------------------------------------------------
409 // Description:
410 // Called by the AMR Volume Mapper.
411 // Set the flag that tells if the scalars are on point data (0) or
412 // cell data (1).
SetCellFlag(int cellFlag)413 void vtkGPUVolumeRayCastMapper::SetCellFlag(int cellFlag)
414 {
415   this->CellFlag=cellFlag;
416 }
417 
418 // ----------------------------------------------------------------------------
CreateCanonicalView(vtkRenderer * ren,vtkVolume * volume,vtkImageData * image,int vtkNotUsed (blend_mode),double viewDirection[3],double viewUp[3])419 void vtkGPUVolumeRayCastMapper::CreateCanonicalView(
420   vtkRenderer *ren,
421   vtkVolume *volume,
422   vtkImageData *image,
423   int vtkNotUsed(blend_mode),
424   double viewDirection[3],
425   double viewUp[3])
426 {
427   this->GeneratingCanonicalView = 1;
428   int oldSwap = ren->GetRenderWindow()->GetSwapBuffers();
429   ren->GetRenderWindow()->SwapBuffersOff();
430 
431   int dim[3];
432   image->GetDimensions(dim);
433   int *size = ren->GetRenderWindow()->GetSize();
434 
435   vtkImageData *bigImage = vtkImageData::New();
436   bigImage->SetDimensions(size[0], size[1], 1);
437   bigImage->AllocateScalars(VTK_UNSIGNED_CHAR, 3);
438 
439   this->CanonicalViewImageData = bigImage;
440 
441   double scale[2];
442   scale[0] = dim[0] / static_cast<double>(size[0]);
443   scale[1] = dim[1] / static_cast<double>(size[1]);
444 
445   // Save the visibility flags of the renderers and set all to false except
446   // for the ren.
447   vtkRendererCollection *renderers=ren->GetRenderWindow()->GetRenderers();
448   int numberOfRenderers=renderers->GetNumberOfItems();
449 
450   bool *rendererVisibilities=new bool[numberOfRenderers];
451   renderers->InitTraversal();
452   int i=0;
453   while(i<numberOfRenderers)
454     {
455     vtkRenderer *r=renderers->GetNextItem();
456     rendererVisibilities[i]=r->GetDraw()==1;
457     if(r!=ren)
458       {
459       r->SetDraw(false);
460       }
461     ++i;
462     }
463 
464   // Save the visibility flags of the props and set all to false except
465   // for the volume.
466 
467   vtkPropCollection *props=ren->GetViewProps();
468   int numberOfProps=props->GetNumberOfItems();
469 
470   bool *propVisibilities=new bool[numberOfProps];
471   props->InitTraversal();
472   i=0;
473   while(i<numberOfProps)
474     {
475     vtkProp *p=props->GetNextProp();
476     propVisibilities[i]=p->GetVisibility()==1;
477     if(p!=volume)
478       {
479       p->SetVisibility(false);
480       }
481     ++i;
482     }
483 
484   vtkCamera *savedCamera=ren->GetActiveCamera();
485   savedCamera->Modified();
486   vtkCamera *canonicalViewCamera=vtkCamera::New();
487 
488   // Code from vtkFixedPointVolumeRayCastMapper:
489   double *center=volume->GetCenter();
490   double bounds[6];
491   volume->GetBounds(bounds);
492   double d=sqrt((bounds[1]-bounds[0])*(bounds[1]-bounds[0]) +
493                 (bounds[3]-bounds[2])*(bounds[3]-bounds[2]) +
494                 (bounds[5]-bounds[4])*(bounds[5]-bounds[4]));
495 
496   // For now use x distance - need to change this
497   d=bounds[1]-bounds[0];
498 
499   // Set up the camera in parallel
500   canonicalViewCamera->SetFocalPoint(center);
501   canonicalViewCamera->ParallelProjectionOn();
502   canonicalViewCamera->SetPosition(center[0] - d*viewDirection[0],
503                                    center[1] - d*viewDirection[1],
504                                    center[2] - d*viewDirection[2]);
505   canonicalViewCamera->SetViewUp(viewUp);
506   canonicalViewCamera->SetParallelScale(d/2);
507 
508   ren->SetActiveCamera(canonicalViewCamera);
509   ren->GetRenderWindow()->Render();
510 
511   ren->SetActiveCamera(savedCamera);
512   canonicalViewCamera->Delete();
513 
514   // Shrink to image to the desired size
515   vtkImageResample *resample = vtkImageResample::New();
516   resample->SetInputData( bigImage );
517   resample->SetAxisMagnificationFactor(0,scale[0]);
518   resample->SetAxisMagnificationFactor(1,scale[1]);
519   resample->SetAxisMagnificationFactor(2,1);
520   resample->UpdateWholeExtent();
521 
522   // Copy the pixels over
523   image->DeepCopy(resample->GetOutput());
524 
525   bigImage->Delete();
526   resample->Delete();
527 
528   // Restore the visibility flags of the props
529   props->InitTraversal();
530   i=0;
531   while(i<numberOfProps)
532     {
533     vtkProp *p=props->GetNextProp();
534     p->SetVisibility(propVisibilities[i]);
535     ++i;
536     }
537 
538   delete[] propVisibilities;
539 
540   // Restore the visibility flags of the renderers
541   renderers->InitTraversal();
542   i=0;
543   while(i<numberOfRenderers)
544     {
545     vtkRenderer *r=renderers->GetNextItem();
546     r->SetDraw(rendererVisibilities[i]);
547     ++i;
548     }
549 
550   delete[] rendererVisibilities;
551 
552   ren->GetRenderWindow()->SetSwapBuffers(oldSwap);
553   this->CanonicalViewImageData = NULL;
554   this->GeneratingCanonicalView = 0;
555 }
556 
557 // ----------------------------------------------------------------------------
558 // Print method for vtkGPUVolumeRayCastMapper
PrintSelf(ostream & os,vtkIndent indent)559 void vtkGPUVolumeRayCastMapper::PrintSelf(ostream& os, vtkIndent indent)
560 {
561   this->Superclass::PrintSelf(os,indent);
562 
563   os << indent << "AutoAdjustSampleDistances: "
564      << this->AutoAdjustSampleDistances << endl;
565   os << indent << "MinimumImageSampleDistance: "
566      << this->MinimumImageSampleDistance << endl;
567   os << indent << "MaximumImageSampleDistance: "
568      << this->MaximumImageSampleDistance << endl;
569   os << indent << "ImageSampleDistance: " << this->ImageSampleDistance << endl;
570   os << indent << "SampleDistance: " << this->SampleDistance << endl;
571   os << indent << "FinalColorWindow: " << this->FinalColorWindow << endl;
572   os << indent << "FinalColorLevel: " << this->FinalColorLevel << endl;
573   os << indent << "MaskInput: " << this->MaskInput << endl;
574   os << indent << "MaskType: " << this->MaskType << endl;
575   os << indent << "MaskBlendFactor: " << this->MaskBlendFactor << endl;
576   os << indent << "MaxMemoryInBytes: " << this->MaxMemoryInBytes << endl;
577   os << indent << "MaxMemoryFraction: " << this->MaxMemoryFraction << endl;
578   os << indent << "ReportProgress: " << this->ReportProgress << endl;
579 }
580 
581 // ----------------------------------------------------------------------------
582 // Description:
583 // Compute the cropping planes clipped by the bounds of the volume.
584 // The result is put into this->ClippedCroppingRegionPlanes.
585 // NOTE: IT WILL BE MOVED UP TO vtkVolumeMapper after bullet proof usage
586 // in this mapper. Other subclasses will use the ClippedCroppingRegionsPlanes
587 // members instead of CroppingRegionPlanes.
588 // \pre volume_exists: this->GetInput()!=0
589 // \pre valid_cropping: this->Cropping &&
590 //             this->CroppingRegionPlanes[0]<this->CroppingRegionPlanes[1] &&
591 //             this->CroppingRegionPlanes[2]<this->CroppingRegionPlanes[3] &&
592 //             this->CroppingRegionPlanes[4]<this->CroppingRegionPlanes[5])
ClipCroppingRegionPlanes()593 void vtkGPUVolumeRayCastMapper::ClipCroppingRegionPlanes()
594 {
595   assert("pre: volume_exists" && this->GetInput()!=0);
596   assert("pre: valid_cropping" && this->Cropping &&
597          this->CroppingRegionPlanes[0]<this->CroppingRegionPlanes[1] &&
598          this->CroppingRegionPlanes[2]<this->CroppingRegionPlanes[3] &&
599          this->CroppingRegionPlanes[4]<this->CroppingRegionPlanes[5]);
600 
601   // vtkVolumeMapper::Render() will have something like:
602 //  if(this->Cropping && (this->CroppingRegionPlanes[0]>=this->CroppingRegionPlanes[1] ||
603 //                        this->CroppingRegionPlanes[2]>=this->CroppingRegionPlanes[3] ||
604 //                        this->CroppingRegionPlanes[4]>=this->CroppingRegionPlanes[5]))
605 //    {
606 //    // silentely  stop because the cropping is not valid.
607 //    return;
608 //    }
609 
610   double volBounds[6];
611   this->GetInput()->GetBounds(volBounds);
612 
613   int i=0;
614   while(i<6)
615     {
616     // max of the mins
617     if(this->CroppingRegionPlanes[i]<volBounds[i])
618       {
619       this->ClippedCroppingRegionPlanes[i]=volBounds[i];
620       }
621     else
622       {
623       this->ClippedCroppingRegionPlanes[i]=this->CroppingRegionPlanes[i];
624       }
625     ++i;
626     // min of the maxs
627     if(this->CroppingRegionPlanes[i]>volBounds[i])
628       {
629       this->ClippedCroppingRegionPlanes[i]=volBounds[i];
630       }
631     else
632       {
633       this->ClippedCroppingRegionPlanes[i]=this->CroppingRegionPlanes[i];
634       }
635     ++i;
636     }
637 }
638 
639 //----------------------------------------------------------------------------
SetMaskTypeToBinary()640 void vtkGPUVolumeRayCastMapper::SetMaskTypeToBinary()
641 {
642   this->MaskType = vtkGPUVolumeRayCastMapper::BinaryMaskType;
643 }
644 
645 //----------------------------------------------------------------------------
SetMaskTypeToLabelMap()646 void vtkGPUVolumeRayCastMapper::SetMaskTypeToLabelMap()
647 {
648   this->MaskType = vtkGPUVolumeRayCastMapper::LabelMapMaskType;
649 }
650