1 #include <sstream>
2 
3 #include "vtkOpenGLGPUVolumeRayCastMapper.h"
4 #include "vtkVolumeInputHelper.h"
5 #include "vtkOpenGLRenderWindow.h"
6 #include "vtkOpenGLTransferFunction2D.h"
7 #include "vtkOpenGLVolumeGradientOpacityTable.h"
8 #include "vtkOpenGLVolumeOpacityTable.h"
9 #include "vtkOpenGLVolumeRGBTable.h"
10 #include "vtkRenderer.h"
11 #include "vtkShaderProgram.h"
12 #include "vtkVolume.h"
13 #include "vtkVolumeProperty.h"
14 #include "vtkVolumeTexture.h"
15 
16 
17 
vtkVolumeInputHelper(vtkSmartPointer<vtkVolumeTexture> tex,vtkVolume * vol)18 vtkVolumeInputHelper::vtkVolumeInputHelper(vtkSmartPointer<vtkVolumeTexture> tex,
19   vtkVolume* vol)
20 : Texture(tex)
21 , Volume(vol)
22 {
23 };
24 
RefreshTransferFunction(vtkRenderer * ren,const int uniformIndex,const int blendMode,const float samplingDist)25 void vtkVolumeInputHelper::RefreshTransferFunction(vtkRenderer* ren, const int uniformIndex,
26   const int blendMode, const float samplingDist)
27 {
28   if (this->InitializeTransfer ||
29     this->Volume->GetProperty()->GetMTime() > this->LutInit.GetMTime())
30   {
31     this->InitializeTransferFunction(ren, uniformIndex);
32   }
33   this->UpdateTransferFunctions(ren, blendMode, samplingDist);
34 }
35 
InitializeTransferFunction(vtkRenderer * ren,const int index)36 void vtkVolumeInputHelper::InitializeTransferFunction(vtkRenderer* ren, const int index)
37 {
38   const int transferMode =
39     this->Volume->GetProperty()->GetTransferFunctionMode();
40   switch(transferMode)
41   {
42     case vtkVolumeProperty::TF_2D:
43       this->CreateTransferFunction2D(ren, index);
44       break;
45 
46     case vtkVolumeProperty::TF_1D:
47     default:
48       this->CreateTransferFunction1D(ren, index);
49   }
50   this->InitializeTransfer = false;
51 }
52 
UpdateTransferFunctions(vtkRenderer * ren,const int blendMode,const float samplingDist)53 void vtkVolumeInputHelper::UpdateTransferFunctions(vtkRenderer* ren, const int blendMode,
54   const float samplingDist)
55 {
56   auto vol = this->Volume;
57   const int transferMode = vol->GetProperty()->GetTransferFunctionMode();
58   const int numComp =
59     this->Texture->GetLoadedScalars()->GetNumberOfComponents();
60   switch(transferMode)
61   {
62     case vtkVolumeProperty::TF_1D:
63       switch(this->ComponentMode)
64       {
65         case vtkVolumeInputHelper::INDEPENDENT:
66           for (int i = 0; i < numComp; ++i)
67           {
68             this->UpdateOpacityTransferFunction(ren, vol, i,
69               blendMode, samplingDist);
70             this->UpdateGradientOpacityTransferFunction(ren, vol, i,
71               samplingDist);
72             this->UpdateColorTransferFunction(ren, vol, i);
73           }
74           break;
75         default: // RGBA or LA
76           this->UpdateOpacityTransferFunction(ren, vol, numComp - 1,
77             blendMode, samplingDist);
78           this->UpdateGradientOpacityTransferFunction(ren, vol, numComp - 1,
79             samplingDist);
80           this->UpdateColorTransferFunction(ren, vol, 0);
81       }
82       break;
83 
84     case vtkVolumeProperty::TF_2D:
85       switch(this->ComponentMode)
86       {
87         case vtkVolumeInputHelper::INDEPENDENT:
88           for (int i = 0; i < numComp; ++i)
89           {
90             this->UpdateTransferFunction2D(ren, i);
91           }
92           break;
93         default: // RGBA or LA
94           this->UpdateTransferFunction2D(ren, 0);
95       }
96       break;
97   }
98 }
99 
UpdateOpacityTransferFunction(vtkRenderer * ren,vtkVolume * vol,unsigned int component,const int blendMode,const float samplingDist)100 int vtkVolumeInputHelper::UpdateOpacityTransferFunction(vtkRenderer* ren, vtkVolume* vol,
101   unsigned int component, const int blendMode, const float samplingDist)
102 {
103   vtkVolumeProperty* volumeProperty = vol->GetProperty();
104 
105   // Use the first LUT when using dependent components
106   unsigned int lookupTableIndex = volumeProperty->GetIndependentComponents() ?
107                                   component : 0;
108   vtkPiecewiseFunction* scalarOpacity =
109     volumeProperty->GetScalarOpacity(lookupTableIndex);
110 
111   auto volumeTex = this->Texture.GetPointer();
112   double componentRange[2];
113   if (scalarOpacity->GetSize() < 1 ||
114       this->ScalarOpacityRangeType == vtkGPUVolumeRayCastMapper::SCALAR)
115   {
116     for (int i = 0; i < 2; ++i)
117     {
118       componentRange[i] = volumeTex->ScalarRange[component][i];
119     }
120   }
121   else
122   {
123     scalarOpacity->GetRange(componentRange);
124   }
125 
126 
127   if (scalarOpacity->GetSize() < 1)
128   {
129     scalarOpacity->AddPoint(componentRange[0], 0.0);
130     scalarOpacity->AddPoint(componentRange[1], 0.5);
131   }
132 
133   int filterVal =
134     volumeProperty->GetInterpolationType() == VTK_LINEAR_INTERPOLATION ?
135       vtkTextureObject::Linear : vtkTextureObject::Nearest;
136 
137   this->OpacityTables->GetTable(lookupTableIndex)->Update(
138     scalarOpacity, blendMode,
139     samplingDist,
140     componentRange,
141     volumeProperty->GetScalarOpacityUnitDistance(component),
142 #if GL_ES_VERSION_3_0 != 1
143     filterVal,
144 #else
145     vtkTextureObject::Nearest,
146 #endif
147     vtkOpenGLRenderWindow::SafeDownCast(ren->GetRenderWindow()));
148 
149   return 0;
150 }
151 
UpdateColorTransferFunction(vtkRenderer * ren,vtkVolume * vol,unsigned int component)152 int vtkVolumeInputHelper::UpdateColorTransferFunction(vtkRenderer* ren, vtkVolume* vol,
153   unsigned int component)
154 {
155   vtkVolumeProperty* volumeProperty = vol->GetProperty();
156 
157   // Build the colormap in a 1D texture. 1D RGB-texture-mapping from scalar
158   // values to color values build the table.
159   vtkColorTransferFunction* colorTransferFunction =
160     volumeProperty->GetRGBTransferFunction(component);
161 
162   auto volumeTex = this->Texture.GetPointer();
163   double componentRange[2];
164   if (colorTransferFunction->GetSize() < 1 ||
165       this->ColorRangeType == vtkGPUVolumeRayCastMapper::SCALAR)
166   {
167     for (int i = 0; i < 2; ++i)
168     {
169       componentRange[i] = volumeTex->ScalarRange[component][i];
170     }
171   }
172   else
173   {
174     colorTransferFunction->GetRange(componentRange);
175   }
176 
177   // Add points only if its not being added before
178   if (colorTransferFunction->GetSize() < 1)
179   {
180     colorTransferFunction->AddRGBPoint(componentRange[0], 0.0, 0.0, 0.0);
181     colorTransferFunction->AddRGBPoint(componentRange[1], 1.0, 1.0, 1.0);
182   }
183 
184   int filterVal =
185     volumeProperty->GetInterpolationType() == VTK_LINEAR_INTERPOLATION ?
186       vtkTextureObject::Linear : vtkTextureObject::Nearest;
187 
188   this->RGBTables->GetTable(component)->Update(
189     volumeProperty->GetRGBTransferFunction(component),
190     componentRange,
191 #if GL_ES_VERSION_3_0 != 1
192     filterVal,
193 #else
194     vtkTextureObject::Nearest,
195 #endif
196     vtkOpenGLRenderWindow::SafeDownCast(ren->GetRenderWindow()));
197 
198   return 0;
199 }
200 
UpdateGradientOpacityTransferFunction(vtkRenderer * ren,vtkVolume * vol,unsigned int component,const float samplingDist)201 int vtkVolumeInputHelper::UpdateGradientOpacityTransferFunction(vtkRenderer* ren, vtkVolume* vol,
202   unsigned int component, const float samplingDist)
203 {
204   vtkVolumeProperty* volumeProperty = vol->GetProperty();
205 
206   // Use the first LUT when using dependent components
207   unsigned int lookupTableIndex = volumeProperty->GetIndependentComponents() ?
208                                   component : 0;
209 
210   if (!volumeProperty->HasGradientOpacity(lookupTableIndex) ||
211       !this->GradientOpacityTables)
212   {
213     return 1;
214   }
215 
216   vtkPiecewiseFunction* gradientOpacity =
217     volumeProperty->GetGradientOpacity(lookupTableIndex);
218 
219   auto volumeTex = this->Texture.GetPointer();
220   double componentRange[2];
221   if (gradientOpacity->GetSize() < 1 ||
222       this->GradientOpacityRangeType == vtkGPUVolumeRayCastMapper::SCALAR)
223   {
224     for (int i = 0; i < 2; ++i)
225     {
226       componentRange[i] = volumeTex->ScalarRange[component][i];
227     }
228   }
229   else
230   {
231     gradientOpacity->GetRange(componentRange);
232   }
233 
234   if (gradientOpacity->GetSize() < 1)
235   {
236     gradientOpacity->AddPoint(componentRange[0], 0.0);
237     gradientOpacity->AddPoint(componentRange[1], 0.5);
238   }
239 
240   int filterVal =
241     volumeProperty->GetInterpolationType() == VTK_LINEAR_INTERPOLATION ?
242       vtkTextureObject::Linear : vtkTextureObject::Nearest;
243 
244   this->GradientOpacityTables->GetTable(lookupTableIndex)->Update(
245     gradientOpacity,
246     samplingDist,
247     componentRange,
248     volumeProperty->GetScalarOpacityUnitDistance(component),
249 #if GL_ES_VERSION_3_0 != 1
250     filterVal,
251 #else
252     vtkTextureObject::Nearest,
253 #endif
254     vtkOpenGLRenderWindow::SafeDownCast(ren->GetRenderWindow()));
255 
256   return 0;
257 }
258 
UpdateTransferFunction2D(vtkRenderer * ren,unsigned int component)259 void vtkVolumeInputHelper::UpdateTransferFunction2D(vtkRenderer* ren,
260   unsigned int component)
261 {
262   // Use the first LUT when using dependent components
263   vtkVolumeProperty* prop = this->Volume->GetProperty();
264   unsigned int const lutIndex = prop->GetIndependentComponents() ?
265     component : 0;
266 
267   vtkImageData* transfer2D = prop->GetTransferFunction2D(lutIndex);
268 #if GL_ES_VERSION_3_0 != 1
269   int const interp = prop->GetInterpolationType() == VTK_LINEAR_INTERPOLATION ?
270     vtkTextureObject::Linear : vtkTextureObject::Nearest;
271 #else
272   int const interp = vtkTextureObject::Nearest;
273 #endif
274 
275   this->TransferFunctions2D->GetTable(lutIndex)->Update(transfer2D, interp,
276       vtkOpenGLRenderWindow::SafeDownCast(ren->GetRenderWindow()));
277 }
278 
ActivateTransferFunction(vtkShaderProgram * prog,const int blendMode)279 void vtkVolumeInputHelper::ActivateTransferFunction(vtkShaderProgram* prog, const int blendMode)
280 {
281   int const transferMode =
282     this->Volume->GetProperty()->GetTransferFunctionMode();
283   int const numActiveLuts = this->ComponentMode == INDEPENDENT ?
284     Texture->GetLoadedScalars()->GetNumberOfComponents() : 1;
285   switch (transferMode)
286   {
287     case vtkVolumeProperty::TF_1D:
288       for (int i = 0; i < numActiveLuts; ++i)
289       {
290         this->OpacityTables->GetTable(i)->Activate();
291         prog->SetUniformi(
292           this->OpacityTablesMap[i].c_str(),
293           this->OpacityTables->GetTable(i)->GetTextureUnit());
294 
295         if (blendMode != vtkGPUVolumeRayCastMapper::ADDITIVE_BLEND)
296         {
297           this->RGBTables->GetTable(i)->Activate();
298           prog->SetUniformi(
299             this->RGBTablesMap[i].c_str(),
300             this->RGBTables->GetTable(i)->GetTextureUnit());
301         }
302 
303         if (this->GradientOpacityTables)
304         {
305           this->GradientOpacityTables->GetTable(i)->Activate();
306           prog->SetUniformi(
307             this->GradientOpacityTablesMap[i].c_str(),
308             this->GradientOpacityTables->GetTable(i)->GetTextureUnit());
309         }
310       }
311       break;
312     case vtkVolumeProperty::TF_2D:
313       for (int i = 0; i < numActiveLuts; ++i)
314       {
315         vtkOpenGLTransferFunction2D* table =
316         this->TransferFunctions2D->GetTable(i);
317         table->Activate();
318         prog->SetUniformi(this->TransferFunctions2DMap[i].c_str(),
319           table->GetTextureUnit());
320       }
321       break;
322   }
323 }
324 
DeactivateTransferFunction(const int blendMode)325 void vtkVolumeInputHelper::DeactivateTransferFunction(const int blendMode)
326 {
327   int const transferMode =
328     this->Volume->GetProperty()->GetTransferFunctionMode();
329   int const numActiveLuts = this->ComponentMode == INDEPENDENT ?
330     Texture->GetLoadedScalars()->GetNumberOfComponents() : 1;
331   switch(transferMode)
332   {
333     case vtkVolumeProperty::TF_1D:
334       for (int i = 0; i < numActiveLuts; ++i)
335       {
336         this->OpacityTables->GetTable(i)->Deactivate();
337         if (blendMode != vtkGPUVolumeRayCastMapper::ADDITIVE_BLEND)
338         {
339           this->RGBTables->GetTable(i)->Deactivate();
340         }
341         if (this->GradientOpacityTables)
342         {
343           this->GradientOpacityTables->GetTable(i)->Deactivate();
344         }
345       }
346       break;
347     case vtkVolumeProperty::TF_2D:
348       for (int i = 0; i < numActiveLuts; ++i)
349       {
350         this->TransferFunctions2D->GetTable(i)->Deactivate();
351       }
352       break;
353   }
354 }
355 
CreateTransferFunction1D(vtkRenderer * ren,const int index)356 void vtkVolumeInputHelper::CreateTransferFunction1D(vtkRenderer* ren, const int index)
357 {
358   this->ReleaseGraphicsTransfer1D(ren->GetRenderWindow());
359 
360   int const numActiveLuts = this->ComponentMode == INDEPENDENT ?
361     Texture->GetLoadedScalars()->GetNumberOfComponents() : 1;
362 
363   // Create RGB and opacity (scalar and gradient) lookup tables. Up to four
364   // components are supported in single-input independentComponents mode.
365   this->RGBTables = vtkSmartPointer<vtkOpenGLVolumeRGBTables>::New();
366     this->RGBTables->Create(numActiveLuts);
367   this->OpacityTables = vtkSmartPointer<vtkOpenGLVolumeOpacityTables>::New();
368     this->OpacityTables->Create(numActiveLuts);
369   this->GradientOpacityTables =
370     vtkSmartPointer<vtkOpenGLVolumeGradientOpacityTables>::New();
371   this->GradientOpacityTables->Create(numActiveLuts);
372 
373   this->OpacityTablesMap.clear();
374   this->RGBTablesMap.clear();
375   this->GradientOpacityTablesMap.clear();
376 
377   std::ostringstream idx;
378   idx << index;
379 
380   this->GradientCacheName = "g_gradients_" + idx.str();
381 
382   for (int i = 0; i < numActiveLuts; ++i)
383   {
384     std::ostringstream comp;
385     comp << "[" << i << "]";
386 
387     this->OpacityTablesMap[i] =
388       "in_opacityTransferFunc_" + idx.str() + comp.str();
389     this->RGBTablesMap[i] = "in_colorTransferFunc_" + idx.str() + comp.str();
390 
391     // Unlike color and scalar-op, graident-op is optional (some inputs may
392     // or may not have gradient-op active).
393     if (this->Volume->GetProperty()->HasGradientOpacity())
394     {
395       this->GradientOpacityTablesMap[i] =
396         "in_gradientTransferFunc_" + idx.str() + comp.str();
397     }
398   }
399 
400   this->LutInit.Modified();
401 }
402 
CreateTransferFunction2D(vtkRenderer * ren,const int index)403 void vtkVolumeInputHelper::CreateTransferFunction2D(vtkRenderer* ren,
404   const int index)
405 {
406   this->ReleaseGraphicsTransfer2D(ren->GetRenderWindow());
407 
408   unsigned int const num = this->ComponentMode == INDEPENDENT ?
409      Texture->GetLoadedScalars()->GetNumberOfComponents() : 1;
410 
411   this->TransferFunctions2D =
412     vtkSmartPointer<vtkOpenGLTransferFunctions2D>::New();
413   this->TransferFunctions2D->Create(num);
414 
415   std::ostringstream idx;
416   idx << index;
417 
418   this->GradientCacheName = "g_gradients_" + idx.str();
419 
420   for (unsigned int i = 0; i < num; i++)
421   {
422     std::ostringstream comp;
423     comp << "[" << i << "]";
424 
425     this->TransferFunctions2DMap[i] = "in_transfer2D_" + idx.str() + comp.str();
426   }
427 
428   this->LutInit.Modified();
429 }
430 
ReleaseGraphicsResources(vtkWindow * window)431 void vtkVolumeInputHelper::ReleaseGraphicsResources(vtkWindow* window)
432 {
433   this->ReleaseGraphicsTransfer1D(window);
434   this->ReleaseGraphicsTransfer2D(window);
435   this->Texture->ReleaseGraphicsResources(window);
436   this->InitializeTransfer = true;
437 }
438 
ReleaseGraphicsTransfer1D(vtkWindow * window)439 void vtkVolumeInputHelper::ReleaseGraphicsTransfer1D(vtkWindow* window)
440 {
441   if (this->RGBTables)
442   {
443     this->RGBTables->ReleaseGraphicsResources(window);
444   }
445   this->RGBTables = nullptr;
446 
447   if (this->OpacityTables)
448   {
449     this->OpacityTables->ReleaseGraphicsResources(window);
450   }
451   this->OpacityTables = nullptr;
452 
453   if (this->GradientOpacityTables)
454   {
455     this->GradientOpacityTables->ReleaseGraphicsResources(window);
456   }
457   this->GradientOpacityTables = nullptr;
458 }
459 
ReleaseGraphicsTransfer2D(vtkWindow * window)460 void vtkVolumeInputHelper::ReleaseGraphicsTransfer2D(vtkWindow* window)
461 {
462   if (this->TransferFunctions2D)
463   {
464     this->TransferFunctions2D->ReleaseGraphicsResources(window);
465   }
466   this->TransferFunctions2D = nullptr;
467 }
468 
ForceTransferInit()469 void vtkVolumeInputHelper::ForceTransferInit()
470 {
471   this->InitializeTransfer = true;
472 }
473