From 11c361233ed4392c70b6a2ef58f0853f2ed2fec0 Mon Sep 17 00:00:00 2001
From: Alvaro Sanchez <alvaro.sanchez@kitware.com>
Date: Mon, 27 Mar 2017 18:42:50 -0400
Subject: [PATCH] Implemented TransferFunction2D initialization and clean-up.

Activating and deactivating TransferFunc2D texture.
---
 Rendering/Core/vtkVolumeProperty.h            |  11 +-
 .../vtkOpenGLGPUVolumeRayCastMapper.cxx       | 283 ++++++++++++------
 .../vtkOpenGLTransferFunction2D.h             |   5 +-
 3 files changed, 204 insertions(+), 95 deletions(-)

diff --git a/Rendering/Core/vtkVolumeProperty.h b/Rendering/Core/vtkVolumeProperty.h
index bac377d57d..c0bf4ef521 100644
--- a/Rendering/Core/vtkVolumeProperty.h
+++ b/Rendering/Core/vtkVolumeProperty.h
@@ -232,11 +232,11 @@ public:
   };
 
   enum TransferMode {
-    TF_1D,
+    TF_1D = 0,
     TF_2D
   };
 
-  vtkSetMacro(TransferFunctionMode, int)
+  vtkSetClampMacro(TransferFunctionMode, int, 0, 1)
   vtkGetMacro(TransferFunctionMode, int)
   //@}
 
@@ -285,8 +285,11 @@ public:
    * will not work as in the former case,  GetDisableGradientOpacity returns
    * false by default and in the later case, a default gradient opacity will be created.
    */
-  bool HasGradientOpacity(int index=0) {
-    return (this->GradientOpacity[index] != NULL);
+  bool HasGradientOpacity(int index = 0) {
+    switch(this->TransferFunctionMode) {
+      case TF_1D: return (this->GradientOpacity[index] != NULL);
+      case TF_2D: return true;
+    }
   }
 
   //@{
diff --git a/Rendering/VolumeOpenGL2/vtkOpenGLGPUVolumeRayCastMapper.cxx b/Rendering/VolumeOpenGL2/vtkOpenGLGPUVolumeRayCastMapper.cxx
index 0ff4294f51..e8b14d03d9 100644
--- a/Rendering/VolumeOpenGL2/vtkOpenGLGPUVolumeRayCastMapper.cxx
+++ b/Rendering/VolumeOpenGL2/vtkOpenGLGPUVolumeRayCastMapper.cxx
@@ -118,6 +118,7 @@ public:
     this->Mask1RGBTable = 0;
     this->Mask2RGBTable =  0;
     this->GradientOpacityTables = 0;
+    this->TransferFunctions2D = NULL;
     this->CurrentMask = 0;
     this->Dimensions[0] = this->Dimensions[1] = this->Dimensions[2] = -1;
     this->TextureSize[0] = this->TextureSize[1] = this->TextureSize[2] = -1;
@@ -239,7 +240,8 @@ public:
       this->ImageSampleVAO->Delete();
       this->ImageSampleVAO = NULL;
     }
-    this->DeleteTransferFunctions();
+    this->DeleteTransfer1D();
+    this->DeleteTransfer2D();
 
     delete this->MaskTextures;
 
@@ -269,12 +271,21 @@ public:
   static void ToFloat(T (&in)[4][2], float (&out)[4][2]);
 
   ///@{
+  /**
+   * \brief Setup and clean-up 1D and 2D transfer functions.
+   */
   void InitializeTransferFunction(vtkRenderer* ren, vtkVolume* vol,
                   int noOfComponents, int independentComponents);
+
   void SetupTransferFunction1D(vtkRenderer* ren, vtkVolume* vol,
                   int noOfComponents, int independentComponents);
+  void ReleaseGraphicsTransfer1D(vtkWindow* window);
+  void DeleteTransfer1D();
+
   void SetupTransferFunction2D(vtkRenderer* ren, vtkVolume* vol,
                   int noOfComponents, int independentComponents);
+  void ReleaseGraphicsTransfer2D(vtkWindow* window);
+  void DeleteTransfer2D();
   ///@}
 
   bool LoadMask(vtkRenderer* ren, vtkImageData* input,
@@ -284,9 +295,6 @@ public:
   bool LoadData(vtkRenderer* ren, vtkVolume* vol, vtkVolumeProperty* volProp,
     vtkImageData* input, vtkDataArray* scalars);
 
-  void DeleteTransferFunctions();
-  void ReleaseGraphicsTransfer1D(vtkWindow* window);
-
   void ComputeBounds(vtkImageData* input);
 
   // Update OpenGL volume information
@@ -298,16 +306,18 @@ public:
                                   vtkVolume* vol,
                                   unsigned int component);
 
-  // Update opacity transfer function (not gradient opacity)
+  // Scalar opacity
   int UpdateOpacityTransferFunction(vtkRenderer* ren,
                                     vtkVolume* vol,
                                     unsigned int component);
 
-  // Update gradient opacity function
   int UpdateGradientOpacityTransferFunction(vtkRenderer* ren,
                                             vtkVolume* vol,
                                             unsigned int component);
 
+  void UpdateTransferFunction2D(vtkRenderer* ren, vtkVolume* vol,
+                                unsigned int component);
+
   // Update noise texture (used to reduce rendering artifacts
   // specifically banding effects)
   void CreateNoiseTexture(vtkRenderer* ren);
@@ -460,6 +470,10 @@ public:
   vtkOpenGLVolumeGradientOpacityTables* GradientOpacityTables;
   std::map<int, std::string> GradientOpacityTablesMap;
 
+  vtkOpenGLTransferFunctions2D* TransferFunctions2D;
+  std::map<int, std::string> TransferFunctions2DMap;
+  vtkTimeStamp Transfer2DTime;
+
   vtkTimeStamp ShaderBuildTime;
 
   vtkNew<vtkMatrix4x4> TextureToDataSetMat;
@@ -598,7 +612,7 @@ void vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::SetupTransferFunction1D(
   int independentComponents)
 {
   this->ReleaseGraphicsTransfer1D(ren->GetRenderWindow());
-  this->DeleteTransferFunctions();
+  this->DeleteTransfer1D();
 
   // Create RGB lookup table
   if (noOfComponents > 1 && independentComponents)
@@ -653,6 +667,8 @@ void vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::SetupTransferFunction1D(
   this->GradientOpacityTablesMap.clear();
 
   std::ostringstream numeric;
+  /// TODO fix this:  noOfComponents should be either noOfComponents or 1
+  /// depnding on the above
   for (int i = 0; i < noOfComponents; ++i)
   {
     numeric << i;
@@ -680,10 +696,30 @@ void vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::SetupTransferFunction1D(
 
 //----------------------------------------------------------------------------
 void vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::SetupTransferFunction2D(
-  vtkRenderer* vtkNotUsed(ren), vtkVolume* vol, int noOfComponents,
+  vtkRenderer* ren, vtkVolume* vol, int noOfComponents,
   int independentComponents)
 {
-  std::cout << "->>> Setting up 2D TF !!!\n";
+  this->ReleaseGraphicsTransfer2D(ren->GetRenderWindow());
+  this->DeleteTransfer2D();
+
+  unsigned int const num = (noOfComponents > 1 && independentComponents) ?
+    noOfComponents : 1;
+  this->TransferFunctions2D = new vtkOpenGLTransferFunctions2D(num);
+
+  std::ostringstream indexStream;
+  const std::string baseName = "in_transfer2D";
+  for (int i = 0; i < num; i++)
+  {
+    if (i > 0)
+    {
+      indexStream << i;
+    }
+    this->TransferFunctions2DMap[0] = baseName + indexStream.str();
+    indexStream.str("");
+    indexStream.clear();
+  }
+
+  this->Transfer2DTime.Modified();
 }
 
 //----------------------------------------------------------------------------
@@ -800,7 +836,7 @@ void vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::ReleaseGraphicsTransfer1D(
 }
 
 //----------------------------------------------------------------------------
-void vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::DeleteTransferFunctions()
+void vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::DeleteTransfer1D()
 {
   delete this->RGBTables;
   this->RGBTables = NULL;
@@ -824,6 +860,23 @@ void vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::DeleteTransferFunctions()
   this->GradientOpacityTables = NULL;
 }
 
+//----------------------------------------------------------------------------
+void vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::ReleaseGraphicsTransfer2D(
+  vtkWindow* window)
+{
+  if (this->TransferFunctions2D)
+  {
+    this->TransferFunctions2D->ReleaseGraphicsResources(window);
+  }
+}
+
+//----------------------------------------------------------------------------
+void vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::DeleteTransfer2D()
+{
+  delete this->TransferFunctions2D;
+  this->TransferFunctions2D = NULL;
+}
+
 //----------------------------------------------------------------------------
 void vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::ComputeBounds(
   vtkImageData* input)
@@ -961,11 +1014,6 @@ int vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::
   UpdateOpacityTransferFunction(vtkRenderer* ren, vtkVolume* vol,
                                 unsigned int component)
 {
-  if (!vol)
-  {
-    return 1;
-  }
-
   vtkVolumeProperty* volumeProperty = vol->GetProperty();
 
   // Transfer function table index based on whether independent / dependent
@@ -1007,24 +1055,45 @@ int vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::
 }
 
 //----------------------------------------------------------------------------
-int vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::
-  UpdateGradientOpacityTransferFunction(vtkRenderer* ren, vtkVolume* vol,
-                                        unsigned int component)
+void vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::
+  UpdateTransferFunction2D(vtkRenderer* ren, vtkVolume* vol,
+  unsigned int component)
 {
-  if (!vol)
+  vtkVolumeProperty* prop = vol->GetProperty();
+  int const transferMode = prop->GetTransferFunctionMode();
+  if (transferMode != vtkVolumeProperty::TF_2D)
   {
-    return 1;
+    return;
   }
 
+  // Use the first LUT when using dependent components
+  unsigned int const lutIndex = prop->GetIndependentComponents() ?
+    component : 0;
+
+  vtkImageData* transfer2D = prop->GetTransferFunction2D(lutIndex);
+#if GL_ES_VERSION_3_0 != 1
+  int const interp = prop->GetInterpolationType() == VTK_LINEAR_INTERPOLATION ?
+    vtkTextureObject::Linear : vtkTextureObject::Nearest;
+#else
+  int const interp = vtkTextureObject::Nearest;
+#endif
+
+  this->TransferFunctions2D->GetTable(lutIndex)->Update(transfer2D, interp,
+      vtkOpenGLRenderWindow::SafeDownCast(ren->GetRenderWindow()));
+}
+
+//----------------------------------------------------------------------------
+int vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::
+  UpdateGradientOpacityTransferFunction(vtkRenderer* ren, vtkVolume* vol,
+                                        unsigned int component)
+{
   vtkVolumeProperty* volumeProperty = vol->GetProperty();
 
   // Transfer function table index based on whether independent / dependent
   // components. If dependent, use the first gradient opacity transfer function
   unsigned int lookupTableIndex = volumeProperty->GetIndependentComponents() ?
                                   component : 0;
-  // TODO Currently we expect the all of the tables will
-  // be initialized once and if at that time, the gradient
-  // opacity was not enabled then it is not used later.
+
   if (!volumeProperty->HasGradientOpacity(lookupTableIndex) ||
       !this->GradientOpacityTables)
   {
@@ -2652,7 +2721,10 @@ void vtkOpenGLGPUVolumeRayCastMapper::ReleaseGraphicsResources(
   }
 
   this->Impl->ReleaseGraphicsTransfer1D(window);
-  this->Impl->DeleteTransferFunctions();
+  this->Impl->DeleteTransfer1D();
+
+  this->Impl->ReleaseGraphicsTransfer2D(window);
+  this->Impl->DeleteTransfer2D();
 
   this->Impl->ReleaseResourcesTime.Modified();
 }
@@ -2829,29 +2901,41 @@ void vtkOpenGLGPUVolumeRayCastMapper::BuildShader(vtkRenderer* ren,
 
   // Compute methods replacements
   //--------------------------------------------------------------------------
-  fragmentShader = vtkvolume::replace(
-    fragmentShader,
-    "//VTK::ComputeOpacity::Dec",
-    vtkvolume::ComputeOpacityDeclaration(ren, this, vol, noOfComponents,
-                                         independentComponents,
-                                         this->Impl->OpacityTablesMap),
-    true);
-
-  fragmentShader = vtkvolume::replace(
-    fragmentShader,
-    "//VTK::ComputeGradient::Dec",
-    vtkvolume::ComputeGradientDeclaration(ren, this, vol, noOfComponents,
-                                          independentComponents,
-                                          this->Impl->GradientOpacityTablesMap),
-    true);
-
-  fragmentShader = vtkvolume::replace(
-    fragmentShader,
-    "//VTK::ComputeColor::Dec",
-    vtkvolume::ComputeColorDeclaration(ren, this, vol, noOfComponents,
-                                       independentComponents,
-                                       this->Impl->RGBTablesMap),
-    true);
+  switch(volumeProperty->GetTransferFunctionMode())
+  {
+    case vtkVolumeProperty::TF_1D:
+      fragmentShader = vtkvolume::replace(
+        fragmentShader,
+        "//VTK::ComputeOpacity::Dec",
+        vtkvolume::ComputeOpacityDeclaration(ren, this, vol, noOfComponents,
+                                             independentComponents,
+                                             this->Impl->OpacityTablesMap),
+        true);
+
+      fragmentShader = vtkvolume::replace(
+        fragmentShader,
+        "//VTK::ComputeGradient::Dec",
+        vtkvolume::ComputeGradientDeclaration(ren, this, vol, noOfComponents,
+                                              independentComponents,
+                                              this->Impl->GradientOpacityTablesMap),
+        true);
+
+      fragmentShader = vtkvolume::replace(
+        fragmentShader,
+        "//VTK::ComputeColor::Dec",
+        vtkvolume::ComputeColorDeclaration(ren, this, vol, noOfComponents,
+                                           independentComponents,
+                                           this->Impl->RGBTablesMap),
+        true);
+      break;
+    case vtkVolumeProperty::TF_2D:
+//      fragmentShader = vtkvolume::replace(fragmentShader,
+//        "//VTK::ComputeColor::Dec",
+//        vtkvolume::TransferFunction2DDeclaration(ren, this,, vol, noOfComponents,
+//          independentComponents, this->Impl->TransferFunctions2DMap),
+//        true);
+      break;
+  }
 
   fragmentShader = vtkvolume::replace(
     fragmentShader,
@@ -3155,18 +3239,14 @@ void vtkOpenGLGPUVolumeRayCastMapper::GPURender(vtkRenderer* ren,
 
   // Update in_volume first to make sure states are current
   vol->Update();
-
-  // Get the input
   vtkImageData* input = this->GetTransformedInput();
 
-  // Get the volume property (must have one)
+  // vtkVolume ensures the property will be valid
   vtkVolumeProperty* volumeProperty = vol->GetProperty();
-
-  // Get the camera
   vtkOpenGLCamera* cam = vtkOpenGLCamera::SafeDownCast(ren->GetActiveCamera());
 
   // Check whether we have independent components or not
-  int independentComponents = volumeProperty->GetIndependentComponents();
+  int const independentComponents = volumeProperty->GetIndependentComponents();
 
   this->Impl->CheckPropertyKeys(vol);
 
@@ -3194,15 +3274,12 @@ void vtkOpenGLGPUVolumeRayCastMapper::GPURender(vtkRenderer* ren,
                           this->ArrayName,
                           this->CellFlag);
 
-  // How many components are there?
-  int noOfComponents = scalars->GetNumberOfComponents();
-
   // Allocate important variables
+  int const noOfComponents = scalars->GetNumberOfComponents();
   this->Impl->Bias.resize(noOfComponents, 0.0);
 
   if (this->Impl->NeedToInitializeResources ||
-      (volumeProperty->GetMTime() >
-       this->Impl->InitializationTime.GetMTime()))
+    (volumeProperty->GetMTime() > this->Impl->InitializationTime.GetMTime()))
   {
     this->Impl->InitializeTransferFunction(ren, vol, noOfComponents,
                            independentComponents);
@@ -3254,6 +3331,7 @@ void vtkOpenGLGPUVolumeRayCastMapper::GPURender(vtkRenderer* ren,
       this->Impl->UpdateOpacityTransferFunction(ren, vol, i);
       this->Impl->UpdateGradientOpacityTransferFunction(ren, vol, i);
       this->Impl->UpdateColorTransferFunction(ren, vol, i);
+      this->Impl->UpdateTransferFunction2D(ren, vol, i);
     }
   }
   else
@@ -3264,6 +3342,7 @@ void vtkOpenGLGPUVolumeRayCastMapper::GPURender(vtkRenderer* ren,
       this->Impl->UpdateGradientOpacityTransferFunction(ren, vol,
                                                         noOfComponents - 1);
       this->Impl->UpdateColorTransferFunction(ren, vol, 0);
+      this->Impl->UpdateTransferFunction2D(ren, vol, 0);
     }
   }
 
@@ -3538,30 +3617,45 @@ void vtkOpenGLGPUVolumeRayCastMapper::DoGPURender(vtkRenderer* ren,
   // Bind textures
   //--------------------------------------------------------------------------
   // Opacity, color, and gradient opacity samplers / textures
-  int numberOfSamplers = (independentComponents ? noOfComponents : 1);
-
-  for (int i = 0; i < numberOfSamplers; ++i)
+  int const numberOfSamplers = (independentComponents ? noOfComponents : 1);
+  int const transferMode = volumeProperty->GetTransferFunctionMode();
+  switch (transferMode)
   {
-    this->Impl->OpacityTables->GetTable(i)->Activate();
-    prog->SetUniformi(
-      this->Impl->OpacityTablesMap[i].c_str(),
-      this->Impl->OpacityTables->GetTable(i)->GetTextureUnit());
+    case vtkVolumeProperty::TF_1D:
+      for (int i = 0; i < numberOfSamplers; ++i)
+      {
+        this->Impl->OpacityTables->GetTable(i)->Activate();
+        prog->SetUniformi(
+          this->Impl->OpacityTablesMap[i].c_str(),
+          this->Impl->OpacityTables->GetTable(i)->GetTextureUnit());
 
-    if (this->BlendMode != vtkGPUVolumeRayCastMapper::ADDITIVE_BLEND)
-    {
-      this->Impl->RGBTables->GetTable(i)->Activate();
-      prog->SetUniformi(
-        this->Impl->RGBTablesMap[i].c_str(),
-        this->Impl->RGBTables->GetTable(i)->GetTextureUnit());
-    }
+        if (this->BlendMode != vtkGPUVolumeRayCastMapper::ADDITIVE_BLEND)
+        {
+          this->Impl->RGBTables->GetTable(i)->Activate();
+          prog->SetUniformi(
+            this->Impl->RGBTablesMap[i].c_str(),
+            this->Impl->RGBTables->GetTable(i)->GetTextureUnit());
+        }
 
-    if (this->Impl->GradientOpacityTables)
-    {
-      this->Impl->GradientOpacityTables->GetTable(i)->Activate();
-      prog->SetUniformi(
-        this->Impl->GradientOpacityTablesMap[i].c_str(),
-        this->Impl->GradientOpacityTables->GetTable(i)->GetTextureUnit());
-    }
+        if (this->Impl->GradientOpacityTables)
+        {
+          this->Impl->GradientOpacityTables->GetTable(i)->Activate();
+          prog->SetUniformi(
+            this->Impl->GradientOpacityTablesMap[i].c_str(),
+            this->Impl->GradientOpacityTables->GetTable(i)->GetTextureUnit());
+        }
+      }
+      break;
+    case vtkVolumeProperty::TF_2D:
+      for (int i = 0; i < numberOfSamplers; ++i)
+      {
+        vtkOpenGLTransferFunction2D* table =
+        this->Impl->TransferFunctions2D->GetTable(i);
+        table->Activate();
+        prog->SetUniformi(this->Impl->TransferFunctions2DMap[i].c_str(),
+          table->GetTextureUnit());
+      }
+      break;
   }
 
   if (this->Impl->NoiseTextureObject)
@@ -3821,17 +3915,28 @@ void vtkOpenGLGPUVolumeRayCastMapper::DoGPURender(vtkRenderer* ren,
   }
 #endif
 
-  for (int i = 0; i < numberOfSamplers; ++i)
+  switch(transferMode)
   {
-    this->Impl->OpacityTables->GetTable(i)->Deactivate();
-    if (this->BlendMode != vtkGPUVolumeRayCastMapper::ADDITIVE_BLEND)
-    {
-      this->Impl->RGBTables->GetTable(i)->Deactivate();
-    }
-    if (this->Impl->GradientOpacityTables)
-    {
-      this->Impl->GradientOpacityTables->GetTable(i)->Deactivate();
-    }
+    case vtkVolumeProperty::TF_1D:
+      for (int i = 0; i < numberOfSamplers; ++i)
+      {
+        this->Impl->OpacityTables->GetTable(i)->Deactivate();
+        if (this->BlendMode != vtkGPUVolumeRayCastMapper::ADDITIVE_BLEND)
+        {
+          this->Impl->RGBTables->GetTable(i)->Deactivate();
+        }
+        if (this->Impl->GradientOpacityTables)
+        {
+          this->Impl->GradientOpacityTables->GetTable(i)->Deactivate();
+        }
+      }
+      break;
+    case vtkVolumeProperty::TF_2D:
+      for (int i = 0; i < numberOfSamplers; ++i)
+      {
+        this->Impl->TransferFunctions2D->GetTable(i)->Deactivate();
+      }
+      break;
   }
 
   if (this->Impl->CurrentMask)
diff --git a/Rendering/VolumeOpenGL2/vtkOpenGLTransferFunction2D.h b/Rendering/VolumeOpenGL2/vtkOpenGLTransferFunction2D.h
index ca5cefa06d..7b0f433424 100644
--- a/Rendering/VolumeOpenGL2/vtkOpenGLTransferFunction2D.h
+++ b/Rendering/VolumeOpenGL2/vtkOpenGLTransferFunction2D.h
@@ -64,8 +64,8 @@ public:
   };
 
   //--------------------------------------------------------------------------
-  void Update(vtkImageData* transfer2D, double range[2], int interpolation,
-              vtkOpenGLRenderWindow* renWin)
+  void Update(vtkImageData* transfer2D, int interpolation,
+    vtkOpenGLRenderWindow* renWin)
   {
     if (!this->TextureObject)
     {
@@ -87,6 +87,7 @@ public:
       if (dims[0] != width || dims[1] != height);
       {
         this->ResizeFilter->SetInputData(transfer2D);
+        this->ResizeFilter->SetResizeMethodToOutputDimensions();
         this->ResizeFilter->SetOutputDimensions(width, height, 1);
         this->ResizeFilter->Update();
         data = this->ResizeFilter->GetOutput()->GetPointData()->GetScalars(
-- 
GitLab