From 582ada6077ff23df586032055fd6f6005d621437 Mon Sep 17 00:00:00 2001
From: Alvaro Sanchez <alvaro.sanchez@kitware.com>
Date: Wed, 14 Sep 2016 16:59:28 -0400
Subject: [PATCH] vtkValuePass::FLOATING_POINT supports cell data.

Added support for cell data arrays (Dave DeMarle).
---
 .../Cxx/TestValuePassFloatingPoint.cxx        | 206 ++++++++-------
 .../TestValuePassFloatingPoint.png.md5        |   2 +-
 Rendering/Core/module.cmake                   |   1 -
 Rendering/OpenGL2/vtkOpenGLPolyDataMapper.cxx |  56 ++--
 Rendering/OpenGL2/vtkValuePass.cxx            |  19 +-
 Rendering/OpenGL2/vtkValuePass.h              |   1 +
 Rendering/OpenGL2/vtkValuePassHelper.cxx      | 239 ++++++++++++++----
 Rendering/OpenGL2/vtkValuePassHelper.h        |  33 ++-
 8 files changed, 359 insertions(+), 198 deletions(-)

diff --git a/Rendering/Core/Testing/Cxx/TestValuePassFloatingPoint.cxx b/Rendering/Core/Testing/Cxx/TestValuePassFloatingPoint.cxx
index aada45a3b92..1f343530c47 100644
--- a/Rendering/Core/Testing/Cxx/TestValuePassFloatingPoint.cxx
+++ b/Rendering/Core/Testing/Cxx/TestValuePassFloatingPoint.cxx
@@ -15,59 +15,53 @@
 
 // Description:
 // Tests vtkValuePass in FLOATING_POINT mode. The test generates a 3-component
-// float array ("elevationVector") using the loaded polygonal data.  Polygons
-// are rendered with the ValuePass to its internal floating point frame-buffer.
+// float array ("elevationVector") using the loaded polygonal data (points and cells).
+// Polygons are rendered with the ValuePass to its internal floating point frame-buffer.
 // The rendered float image is then queried from the vtkValuePass and used to
 // generate a color image using vtkLookupTable, the color image is rendered with
 // an image actor on-screen. This is repeated for each component.
 
-#include "vtkRegressionTestImage.h"
-#include "vtkTestUtilities.h"
 #include "vtkActor.h"
+#include "vtkArrayCalculator.h"
+#include "vtkCamera.h"
 #include "vtkCameraPass.h"
-#include "vtkCellArray.h"
+#include "vtkCellData.h"
 #include "vtkElevationFilter.h"
-#include "vtkInformation.h"
+#include "vtkFloatArray.h"
+#include "vtkImageActor.h"
+#include "vtkImageData.h"
+#include "vtkImageMapper3D.h"
+#include "vtkInteractorStyleTrackballCamera.h"
+#include "vtkLookupTable.h"
 #include "vtkOpenGLRenderer.h"
-#include "vtkPLYReader.h"
 #include "vtkPointData.h"
 #include "vtkPointDataToCellData.h"
 #include "vtkPolyData.h"
 #include "vtkPolyDataMapper.h"
-#include "vtkOpenGLPolyDataMapper.h"
+#include "vtkRegressionTestImage.h"
 #include "vtkRenderPassCollection.h"
 #include "vtkRenderWindow.h"
 #include "vtkRenderWindowInteractor.h"
 #include "vtkSequencePass.h"
 #include "vtkSmartPointer.h"
+#include "vtkSphereSource.h"
+#include "vtkTestUtilities.h"
 #include "vtkValuePass.h"
 
-#include "vtkCamera.h"
-#include "vtkInteractorStyleTrackballCamera.h"
-#include "vtkAbstractMapper.h"
-#include "vtkXMLPolyDataReader.h"
-#include "vtkFloatArray.h"
-#include "vtkLookupTable.h"
-#include "vtkColorSeries.h"
-#include "vtkImageData.h"
-#include "vtkImageActor.h"
-#include "vtkImageMapper3D.h"
-#include "vtkArrayCalculator.h"
-
 
-void GenerateElevationArray(vtkSmartPointer<vtkPLYReader> reader)
+void GenerateElevationArray(vtkSmartPointer<vtkPolyDataAlgorithm> source)
 {
-  vtkPolyData* data = reader->GetOutput();
+  vtkPolyData* data = source->GetOutput();
   double* bounds = data->GetBounds();
 
   vtkSmartPointer<vtkElevationFilter> elevation =
     vtkSmartPointer<vtkElevationFilter>::New();
-  elevation->SetInputConnection(reader->GetOutputPort());
+  elevation->SetInputConnection(source->GetOutputPort());
 
-  /// Use vtkElevation to generate an array per component. vtkElevation generates
-  /// a projected distance from each point in the dataset to the line, with respect to
-  /// the LowPoint ([0, 1] in this case. This is different from having the actual
-  /// coordinates of a given point.
+  // Use vtkElevation to generate an array per component. vtkElevation generates
+  // a projected distance from each point in the dataset to the line, with respect to
+  // the LowPoint ([0, 1] in this case. This is different from having the actual
+  // coordinates of a given point.
   for (int c = 0; c < 3; c++)
     {
     std::string name;
@@ -93,7 +87,7 @@ void GenerateElevationArray(vtkSmartPointer<vtkPLYReader> reader)
 
     vtkPolyData* result = vtkPolyData::SafeDownCast(elevation->GetOutput());
     int outCellFlag;
-    /// Enums defined in vtkAbstractMapper
+    // Enums defined in vtkAbstractMapper
     vtkDataArray* elevArray = vtkAbstractMapper::GetScalars(result,
       VTK_SCALAR_MODE_USE_POINT_FIELD_DATA, VTK_GET_ARRAY_BY_NAME/*acc mode*/,
       0/*arr id*/, "Elevation"/*arr name*/, outCellFlag);
@@ -107,10 +101,13 @@ void GenerateElevationArray(vtkSmartPointer<vtkPLYReader> reader)
     data->GetPointData()->AddArray(elevArray);
     }
 
-  /// Generate a 3-component vector array using the single components
-  /// form elevation.
-  vtkSmartPointer<vtkArrayCalculator> calc = vtkSmartPointer<vtkArrayCalculator>::New();
-  calc->SetInputConnection(reader->GetOutputPort());
+  // Generate a 3-component vector array using the single components
+  // form elevation
+
+  // Point data
+  vtkSmartPointer<vtkArrayCalculator> calc =
+    vtkSmartPointer<vtkArrayCalculator>::New();
+  calc->SetInputConnection(source->GetOutputPort());
   calc->SetAttributeModeToUsePointData();
   calc->AddScalarArrayName("delta_x");
   calc->AddScalarArrayName("delta_y");
@@ -119,39 +116,68 @@ void GenerateElevationArray(vtkSmartPointer<vtkPLYReader> reader)
   calc->SetResultArrayName("elevationVector");
   calc->Update();
 
-  vtkPolyData* result = vtkPolyData::SafeDownCast(calc->GetOutput());
-  int outCellFlag;
-  vtkDataArray* coordArray = vtkAbstractMapper::GetScalars(result,
-    VTK_SCALAR_MODE_USE_POINT_FIELD_DATA, VTK_GET_ARRAY_BY_NAME/*acc mode*/,
-    0/*arr id*/, "elevationVector", outCellFlag);
-  if (!coordArray)
+  // Cell data
+  vtkSmartPointer<vtkPointDataToCellData> p2c =
+    vtkSmartPointer<vtkPointDataToCellData>::New();
+  p2c->SetInputConnection(calc->GetOutputPort());
+  p2c->PassPointDataOn();
+  p2c->Update();
+
+  /// Include the elevation vector (point and cell data) in the original data
+  vtkPolyData* outputP2c = vtkPolyData::SafeDownCast(p2c->GetOutput());
+  data->GetPointData()->AddArray(calc->GetOutput()->GetPointData()->GetArray(
+    "elevationVector"));
+  data->GetCellData()->AddArray(outputP2c->GetCellData()->GetArray("elevationVector"));
+};
+
+//------------------------------------------------------------------------------
+void RenderComponentImages(std::vector<vtkSmartPointer<vtkImageData> >& colorImOut,
+  vtkRenderWindow* window, vtkRenderer* renderer,
+  vtkValuePass* valuePass, int dataMode, char const* name)
+{
+  valuePass->SetInputArrayToProcess(dataMode, name);
+
+  // Prepare a lut to map the floating point values
+  vtkSmartPointer<vtkLookupTable> lut = vtkSmartPointer<vtkLookupTable>::New();
+  lut->SetAlpha(1.0);
+  lut->Build();
+
+  // Render each component in a separate image
+  for(int c = 0; c < 3; c++)
     {
-    std::cout << "->> Error: could not find array!" << std::endl;
-    return;
-    }
+    valuePass->SetInputComponentToProcess(c);
+    window->Render();
 
-  /// Include the elevation vector in the original data
-  data->GetPointData()->AddArray(coordArray);
-}
+    /// Get the resulting values
+    vtkFloatArray* result = valuePass->GetFloatImageDataArray(renderer);
+    std::vector<int> ext = valuePass->GetFloatImageExtents();
 
+    // Map the resulting float image to a color table
+    vtkUnsignedCharArray* colored = lut->MapScalars(result, VTK_COLOR_MODE_DEFAULT,
+      0/* single comp*/);
+
+    // Create an image dataset to render in a quad.
+    vtkSmartPointer<vtkImageData> colorIm = vtkSmartPointer<vtkImageData>::New();
+    colorIm->SetExtent(&(ext.front()));
+    colorIm->GetPointData()->SetScalars(colored);
+    colorImOut.push_back(colorIm);
+    }
+};
 
 ///////////////////////////////////////////////////////////////////////////////
 int TestValuePassFloatingPoint(int argc, char *argv[])
 {
   // Load data
-  const char *fileName =
-    vtkTestUtilities::ExpandDataFileName(argc, argv, "Data/dragon.ply");
-  vtkSmartPointer<vtkPLYReader> reader =
-    vtkSmartPointer<vtkPLYReader>::New();
-  reader->SetFileName(fileName);
-  reader->Update();
+  vtkSmartPointer<vtkSphereSource> sphere = vtkSmartPointer<vtkSphereSource>::New();
+  sphere->SetThetaResolution(8.0);
+  sphere->SetPhiResolution(8.0);
+  sphere->Update();
 
   // Prepare a 3-component array (data will be appended to reader's output)
-  GenerateElevationArray(reader);
-
+  GenerateElevationArray(sphere);
   vtkSmartPointer<vtkPolyDataMapper> mapper =
     vtkSmartPointer<vtkPolyDataMapper>::New();
-  mapper->SetInputConnection(reader->GetOutputPort());
+  mapper->SetInputData(sphere->GetOutput());
   mapper->ScalarVisibilityOn();
 
   vtkSmartPointer<vtkActor> actor =
@@ -168,7 +194,8 @@ int TestValuePassFloatingPoint(int argc, char *argv[])
 
   vtkSmartPointer<vtkRenderWindow> window =
     vtkSmartPointer<vtkRenderWindow>::New();
-  window->SetSize(320, 320);
+  window->SetMultiSamples(0);
+  window->SetSize(640, 640);
 
   vtkSmartPointer<vtkRenderer> renderer =
     vtkSmartPointer<vtkRenderer>::New();
@@ -188,9 +215,11 @@ int TestValuePassFloatingPoint(int argc, char *argv[])
     vtkSmartPointer<vtkValuePass>::New();
   valuePass->SetRenderingMode(RenderingMode);
   valuePass->SetInputComponentToProcess(comp);
-  //valuePass->SetScalarRange(bounds[0], bounds[1]); /*using the full range*/
+  // Initial data mode
   valuePass->SetInputArrayToProcess(VTK_SCALAR_MODE_USE_POINT_FIELD_DATA,
     "elevationVector");
+  //valuePass->SetInputArrayToProcess(VTK_SCALAR_MODE_USE_CELL_FIELD_DATA,
+  //  "elevationVector");
 
   // 3. Add it to a sequence of passes
   vtkSmartPointer<vtkRenderPassCollection> passes =
@@ -214,54 +243,53 @@ int TestValuePassFloatingPoint(int argc, char *argv[])
 
   if (RenderingMode == vtkValuePass::FLOATING_POINT)
     {
-    // Prepare a lut to map the floating point values
-    vtkSmartPointer<vtkLookupTable> lut = vtkSmartPointer<vtkLookupTable>::New();
-    lut->SetAlpha(1.0);
-    //lut->SetRange(elevRange[0], elevRange[1]); /*use the full range*/
-    vtkSmartPointer<vtkColorSeries> series = vtkSmartPointer<vtkColorSeries>::New();
-    series->SetColorScheme(vtkColorSeries::WARM);
-    //series->SetColorScheme(vtkColorSeries::BREWER_DIVERGING_SPECTRAL_11);
-    series->BuildLookupTable(lut, vtkColorSeries::ORDINAL);
-
-    // Render each component in a separate image
-    std::vector<vtkSmartPointer<vtkImageData> > colorImages;
-    for(int c = 0; c < 3; c++)
-      {
-      valuePass->SetInputComponentToProcess(c);
-      window->Render();
-
-      /// Get the resulting values
-      vtkFloatArray* result = valuePass->GetFloatImageDataArray(renderer);
-      std::vector<int> ext = valuePass->GetFloatImageExtents();
-
-      // Map the resulting float image to a color table
-      vtkUnsignedCharArray* colored = lut->MapScalars(result, VTK_COLOR_MODE_DEFAULT,
-        0/* single comp*/);
-
-      // Create an image dataset to render in a quad.
-      vtkSmartPointer<vtkImageData> colorIm = vtkSmartPointer<vtkImageData>::New();
-      colorIm->SetExtent(&(ext.front()));
-      colorIm->GetPointData()->SetScalars(colored);
-      colorImages.push_back(colorIm);
-      }
+    // Render point data images
+    std::vector<vtkSmartPointer<vtkImageData> > colorImagesPoint;
+    RenderComponentImages(colorImagesPoint, window, renderer, valuePass,
+      VTK_SCALAR_MODE_USE_POINT_FIELD_DATA, "elevationVector");
+
+    // Render cell data images
+   std::vector<vtkSmartPointer<vtkImageData> > colorImagesCell;
+    RenderComponentImages(colorImagesCell, window, renderer, valuePass,
+      VTK_SCALAR_MODE_USE_CELL_FIELD_DATA, "elevationVector");
 
-    // Render the image on-screen
+    ////// Render results on-screen
     renderer->RemoveActor(actor);
 
+    // Add image actors to display the point dataArray's componets
     vtkSmartPointer<vtkImageActor> ia_x = vtkSmartPointer<vtkImageActor>::New();
-    ia_x->GetMapper()->SetInputData(colorImages.at(0));
+    ia_x->GetMapper()->SetInputData(colorImagesPoint.at(0));
     renderer->AddActor(ia_x);
 
     vtkSmartPointer<vtkImageActor> ia_y = vtkSmartPointer<vtkImageActor>::New();
     ia_y->RotateX(90);
-    ia_y->GetMapper()->SetInputData(colorImages.at(1));
+    ia_y->GetMapper()->SetInputData(colorImagesPoint.at(1));
     renderer->AddActor(ia_y);
 
     vtkSmartPointer<vtkImageActor> ia_z = vtkSmartPointer<vtkImageActor>::New();
     ia_z->RotateY(-90);
-    ia_z->GetMapper()->SetInputData(colorImages.at(2));
+    ia_z->GetMapper()->SetInputData(colorImagesPoint.at(2));
     renderer->AddActor(ia_z);
 
+    // Add image actors to display cell dataArray's components
+    vtkSmartPointer<vtkImageActor> iacell_x = vtkSmartPointer<vtkImageActor>::New();
+    iacell_x->SetPosition(-500, 600, 600);
+    iacell_x->GetMapper()->SetInputData(colorImagesCell.at(0));
+    renderer->AddActor(iacell_x);
+
+    vtkSmartPointer<vtkImageActor> iacell_y = vtkSmartPointer<vtkImageActor>::New();
+    iacell_y->RotateX(90);
+    iacell_y->SetPosition(-500, 600, 600);
+    iacell_y->GetMapper()->SetInputData(colorImagesCell.at(1));
+    renderer->AddActor(iacell_y);
+
+    vtkSmartPointer<vtkImageActor> iacell_z = vtkSmartPointer<vtkImageActor>::New();
+    iacell_z->RotateY(-90);
+    iacell_z->SetPosition(-500, 600, 600);
+    iacell_z->GetMapper()->SetInputData(colorImagesCell.at(2));
+    renderer->AddActor(iacell_z);
+
+    // Adjust viewpoint
     vtkCamera* cam = renderer->GetActiveCamera();
     cam->SetPosition(2, 2, 2);
     cam->SetFocalPoint(0, 0, 1);
diff --git a/Rendering/Core/Testing/Data/Baseline/TestValuePassFloatingPoint.png.md5 b/Rendering/Core/Testing/Data/Baseline/TestValuePassFloatingPoint.png.md5
index 0ccfda72e3a..7944dcc580b 100644
--- a/Rendering/Core/Testing/Data/Baseline/TestValuePassFloatingPoint.png.md5
+++ b/Rendering/Core/Testing/Data/Baseline/TestValuePassFloatingPoint.png.md5
@@ -1 +1 @@
-c482c9a67076037525ea716826d91077
+98596e51d1cd4844e528adc75f96d193
diff --git a/Rendering/Core/module.cmake b/Rendering/Core/module.cmake
index 17b369e7912..6355e02a994 100644
--- a/Rendering/Core/module.cmake
+++ b/Rendering/Core/module.cmake
@@ -6,7 +6,6 @@ vtk_module(vtkRenderingCore
     vtkIOLegacy
     vtkIOParallel
     vtkIOXML
-    vtkIOPLY
     vtkTestingCore
     vtkTestingRendering
     vtkRendering${VTK_RENDERING_BACKEND}
diff --git a/Rendering/OpenGL2/vtkOpenGLPolyDataMapper.cxx b/Rendering/OpenGL2/vtkOpenGLPolyDataMapper.cxx
index 6f4f62b1f11..c8128739dcb 100644
--- a/Rendering/OpenGL2/vtkOpenGLPolyDataMapper.cxx
+++ b/Rendering/OpenGL2/vtkOpenGLPolyDataMapper.cxx
@@ -211,6 +211,9 @@ void vtkOpenGLPolyDataMapper::ReleaseGraphicsResources(vtkWindow* win)
     {
     this->CellNormalBuffer->ReleaseGraphicsResources();
     }
+
+  this->ValuePassHelper->ReleaseGraphicsResources(win);
+
   if (this->AppleBugPrimIDBuffer)
     {
     this->AppleBugPrimIDBuffer->ReleaseGraphicsResources();
@@ -1487,16 +1490,6 @@ void vtkOpenGLPolyDataMapper::ReplaceShaderValues(
   //cout << "VS: " << shaders[vtkShader::Vertex]->GetSource() << endl;
   //cout << "GS: " << shaders[vtkShader::Geometry]->GetSource() << endl;
   //cout << "FS: " << shaders[vtkShader::Fragment]->GetSource() << endl;
-
-//  std::string vertexShader = shaders[vtkShader::Vertex]->GetSource();
-//  std::string fragmentShader = shaders[vtkShader::Fragment]->GetSource();
-//  std::ofstream file("/home/alvaro/testShaders/PolyData_valuePass.frag");
-//  file << fragmentShader;
-//  file.close();
-//
-//  file.open("/home/alvaro/testShaders/PolyData_valuePass.vert");
-//  file << vertexShader;
-//  file.close();
 }
 
 //-----------------------------------------------------------------------------
@@ -1582,7 +1575,8 @@ bool vtkOpenGLPolyDataMapper::GetNeedToRebuildShaders(
       cellBO.ShaderSourceTime < this->CurrentInput->GetMTime() ||
       cellBO.ShaderSourceTime < this->SelectionStateChanged ||
       cellBO.ShaderSourceTime < renderPassMTime ||
-      cellBO.ShaderSourceTime < this->LightComplexityChanged[&cellBO])
+      cellBO.ShaderSourceTime < this->LightComplexityChanged[&cellBO] ||
+      this->ValuePassHelper->RequiresShaderRebuild(actor))
     {
     return true;
     }
@@ -1616,32 +1610,6 @@ void vtkOpenGLPolyDataMapper::UpdateShaders(
 
     this->BuildShaders(shaders, ren, actor);
 
-
-//  vtkInformation *info = actor->GetPropertyKeys();
-//    if (info && info->Has(vtkValuePass::RENDER_VALUES()))
-//    {
-//  // Load shaders
-//  //---------------
-//  std::string path = "/home/alvaro/testShaders/";
-//  std::string filename = "pv_values";
-//
-//  std::string vfilepath = path + filename + ".vert";
-//  std::ifstream file(vfilepath.c_str());
-//  std::string vert = std::string(std::istreambuf_iterator<char>(file),
-//    std::istreambuf_iterator<char>());
-//  file.close();
-//
-//  std::string ffilepath = path + filename + ".frag";
-//  file.open(ffilepath.c_str());
-//  std::string frag = std::string(std::istreambuf_iterator<char>(file),
-//    std::istreambuf_iterator<char>());
-//  file.close();
-//
-//    shaders[vtkShader::Vertex]->SetSource(vert);
-//    shaders[vtkShader::Fragment]->SetSource(frag);
-//    }
-
-
     // compile and bind the program if needed
     vtkShaderProgram *newShader =
       renWin->GetShaderCache()->ReadyShaderProgram(shaders);
@@ -1742,7 +1710,7 @@ void vtkOpenGLPolyDataMapper::SetMapperShaderParameters(vtkOpenGLHelper &cellBO,
 
     if (this->ValuePassHelper->GetRenderingMode() == vtkValuePass::FLOATING_POINT)
       {
-      this->ValuePassHelper->BindValueBuffer(cellBO);
+      this->ValuePassHelper->BindAttributes(cellBO);
       }
 
     cellBO.AttributeUpdateTime.Modified();
@@ -1796,6 +1764,11 @@ void vtkOpenGLPolyDataMapper::SetMapperShaderParameters(vtkOpenGLHelper &cellBO,
     cellBO.Program->SetUniformi("textureN", tunit);
     }
 
+  if (this->ValuePassHelper->GetRenderingMode() == vtkValuePass::FLOATING_POINT)
+    {
+    this->ValuePassHelper->BindUniforms(cellBO);
+    }
+
   // Handle render pass setup:
   vtkInformation *info = actor->GetPropertyKeys();
   if (info && info->Has(vtkOpenGLRenderPass::RenderPasses()))
@@ -2344,7 +2317,7 @@ void vtkOpenGLPolyDataMapper::RenderPieceStart(vtkRenderer* ren, vtkActor *actor
 
   if (this->ValuePassHelper->GetRenderingMode() == vtkValuePass::FLOATING_POINT)
     {
-    this->ValuePassHelper->UploadValueData(actor, this->CurrentInput);
+    this->ValuePassHelper->RenderPieceStart(actor, this->CurrentInput);
     }
 
   // If we are coloring by texture, then load the texture map.
@@ -2578,6 +2551,11 @@ void vtkOpenGLPolyDataMapper::RenderPieceFinish(vtkRenderer* ren,
     this->CellNormalTexture->Deactivate();
     }
 
+  if (this->ValuePassHelper->GetRenderingMode() == vtkValuePass::FLOATING_POINT)
+    {
+    this->ValuePassHelper->RenderPieceFinish();
+    }
+
   this->UpdateProgress(1.0);
 }
 
diff --git a/Rendering/OpenGL2/vtkValuePass.cxx b/Rendering/OpenGL2/vtkValuePass.cxx
index d33824a1c06..a4212fb24e3 100644
--- a/Rendering/OpenGL2/vtkValuePass.cxx
+++ b/Rendering/OpenGL2/vtkValuePass.cxx
@@ -44,6 +44,7 @@ vtkInformationKeyMacro(vtkValuePass, ARRAY_ID, Integer);
 vtkInformationKeyMacro(vtkValuePass, ARRAY_NAME, String);
 vtkInformationKeyMacro(vtkValuePass, ARRAY_COMPONENT, Integer);
 vtkInformationKeyMacro(vtkValuePass, SCALAR_RANGE, DoubleVector);
+vtkInformationKeyMacro(vtkValuePass, RELOAD_DATA, Integer);
 
 class vtkValuePass::vtkInternals
 {
@@ -55,6 +56,7 @@ public:
   int Component;
   double ScalarRange[2];
   bool ScalarRangeSet;
+  bool ReloadData;
 
   // Array holder for FLOATING_POINT mode. The result pixels are downloaded
   // into this array.
@@ -74,6 +76,7 @@ public:
     this->ScalarRange[0] = 0.0;
     this->ScalarRange[1] = -1.0;
     this->ScalarRangeSet = false;
+    this->ReloadData = true;
     }
 };
 
@@ -111,6 +114,7 @@ void vtkValuePass::SetInputArrayToProcess(int fieldAssociation,
     this->Internals->FieldAssociation = fieldAssociation;
     this->Internals->FieldName = name;
     this->Internals->FieldNameSet = true;
+    this->Internals->ReloadData = true;
     this->Modified();
     }
 }
@@ -126,6 +130,7 @@ void vtkValuePass::SetInputArrayToProcess(int fieldAssociation,
     this->Internals->FieldAssociation = fieldAssociation;
     this->Internals->FieldAttributeType = fieldAttributeType;
     this->Internals->FieldNameSet = false;
+    this->Internals->ReloadData = true;
     this->Modified();
     }
 }
@@ -136,6 +141,7 @@ void vtkValuePass::SetInputComponentToProcess(int component)
   if (this->Internals->Component != component)
     {
     this->Internals->Component = component;
+    this->Internals->ReloadData = true;
     this->Modified();
     }
 }
@@ -153,7 +159,6 @@ void vtkValuePass::SetScalarRange(double min, double max)
     }
 }
 
-
 // ----------------------------------------------------------------------------
 // Description:
 // Perform rendering according to a render state \p s.
@@ -199,6 +204,7 @@ void vtkValuePass::RenderOpaqueGeometry(const vtkRenderState *s)
       {
       keys.TakeReference(vtkInformation::New());
       }
+
     keys->Set(vtkValuePass::RENDER_VALUES(), this->RenderingMode);
     keys->Set(vtkValuePass::SCALAR_MODE(), this->Internals->FieldAssociation);
     keys->Set(vtkValuePass::ARRAY_MODE(), this->Internals->FieldNameSet);
@@ -206,6 +212,11 @@ void vtkValuePass::RenderOpaqueGeometry(const vtkRenderState *s)
     keys->Set(vtkValuePass::ARRAY_NAME(), this->Internals->FieldName.c_str());
     keys->Set(vtkValuePass::ARRAY_COMPONENT(), this->Internals->Component);
     keys->Set(vtkValuePass::SCALAR_RANGE(), this->Internals->ScalarRange, 2);
+    if (this->Internals->ReloadData)
+      {
+      keys->Set(vtkValuePass::RELOAD_DATA(), 1);
+      }
+
     p->SetPropertyKeys(keys);
 
     int rendered =
@@ -235,6 +246,12 @@ void vtkValuePass::RenderOpaqueGeometry(const vtkRenderState *s)
     keys->Remove(vtkValuePass::ARRAY_NAME());
     keys->Remove(vtkValuePass::ARRAY_COMPONENT());
     keys->Remove(vtkValuePass::SCALAR_RANGE());
+    if (this->Internals->ReloadData)
+      {
+      keys->Remove(vtkValuePass::RELOAD_DATA());
+      this->Internals->ReloadData = false;
+      }
+
     p->SetPropertyKeys(keys);
     ++i;
     }
diff --git a/Rendering/OpenGL2/vtkValuePass.h b/Rendering/OpenGL2/vtkValuePass.h
index c92df7e7a8f..94973a48ab2 100644
--- a/Rendering/OpenGL2/vtkValuePass.h
+++ b/Rendering/OpenGL2/vtkValuePass.h
@@ -65,6 +65,7 @@ public:
   static vtkInformationStringKey *ARRAY_NAME();
   static vtkInformationIntegerKey *ARRAY_COMPONENT();
   static vtkInformationDoubleVectorKey *SCALAR_RANGE();
+  static vtkInformationIntegerKey *RELOAD_DATA();
 
   // Description:
   // Perform rendering according to a render state \p s.
diff --git a/Rendering/OpenGL2/vtkValuePassHelper.cxx b/Rendering/OpenGL2/vtkValuePassHelper.cxx
index 23363e13199..8d88c81b838 100644
--- a/Rendering/OpenGL2/vtkValuePassHelper.cxx
+++ b/Rendering/OpenGL2/vtkValuePassHelper.cxx
@@ -1,16 +1,17 @@
-#include "vtkValuePassHelper.h"
+#include "vtkDataArray.h"
+#include "vtkInformation.h"
+#include "vtkMapper.h"
 #include "vtkObjectFactory.h"
-#include "vtkRenderer.h"
-#include "vtkShaderProgram.h"
-#include "vtkOpenGLError.h"
-#include "vtkOpenGLRenderWindow.h"
 #include "vtkOpenGLBufferObject.h"
+#include "vtkOpenGLError.h"
 #include "vtkOpenGLHelper.h"
+#include "vtkOpenGLRenderWindow.h"
 #include "vtkOpenGLVertexArrayObject.h"
+#include "vtkRenderer.h"
+#include "vtkShaderProgram.h"
+#include "vtkTextureObject.h"
 #include "vtkValuePass.h"
-#include "vtkDataArray.h"
-#include "vtkInformation.h"
-#include "vtkMapper.h"
+#include "vtkValuePassHelper.h"
 
 
 vtkStandardNewMacro(vtkValuePassHelper)
@@ -19,31 +20,98 @@ vtkStandardNewMacro(vtkValuePassHelper)
 vtkValuePassHelper::vtkValuePassHelper()
 : ValueBuffer(NULL)
 , ValuePassArray(NULL)
+, CellFloatTexture(NULL)
+, CellFloatBuffer(NULL)
 , RenderingMode(-1)
+, ResourcesAllocated(false)
+, CurrentDataArrayMode(VTK_SCALAR_MODE_USE_POINT_FIELD_DATA)
+, LastDataArrayMode(VTK_SCALAR_MODE_USE_POINT_FIELD_DATA)
 {
 }
 
 //-----------------------------------------------------------------------------
 vtkValuePassHelper::~vtkValuePassHelper()
 {
+  // Graphics resources released previously by the parent mapper or after switching
+  // to INVERTIBLE_LUT mode
   if (this->ValueBuffer)
+    {
     this->ValueBuffer->Delete();
+    this->ValueBuffer = NULL;
+    }
+
+  if (this->CellFloatTexture)
+    {
+    this->CellFloatTexture->Delete();
+    this->CellFloatTexture = NULL;
+    }
+
+  if (this->CellFloatBuffer)
+    {
+    this->CellFloatBuffer->Delete();
+    this->CellFloatBuffer = NULL;
+    }
+}
+
+//-----------------------------------------------------------------------------
+void vtkValuePassHelper::ReleaseGraphicsResources(vtkWindow *win)
+{
+  if (this->CellFloatTexture)
+    {
+    this->CellFloatTexture->ReleaseGraphicsResources(win);
+    this->CellFloatTexture->Delete();
+    this->CellFloatTexture = NULL;
+    }
+
+  if (this->CellFloatBuffer)
+    {
+    this->CellFloatBuffer->ReleaseGraphicsResources();
+    this->CellFloatBuffer->Delete();
+    this->CellFloatBuffer = NULL;
+    }
+
+  if (this->ValueBuffer)
+    {
+    this->ValueBuffer->ReleaseGraphicsResources();
+    this->ValueBuffer->Delete();
+    this->ValueBuffer = NULL;
+    }
+
+  this->ValuePassArray = NULL;
+  this->ResourcesAllocated = false;
+}
+
+//-----------------------------------------------------------------------------
+void vtkValuePassHelper::RenderPieceFinish()
+{
+  if (this->CurrentDataArrayMode == VTK_SCALAR_MODE_USE_CELL_FIELD_DATA)
+    {
+    if (this->CellFloatTexture)
+      {
+      this->CellFloatTexture->Deactivate();
+      }
+    }
 }
 
 //-----------------------------------------------------------------------------
-void vtkValuePassHelper::UploadValueData(vtkActor* actor, vtkDataSet* input)
+void vtkValuePassHelper::RenderPieceStart(vtkActor* actor, vtkDataSet* input)
 {
   vtkInformation *info = actor->GetPropertyKeys();
 
-  // TODO:  Check the Array number / name instead. info does not seem to  update
-  // the timestamp.
-  //if (info->GetMTime() < this->ValueBufferTime)
+  // TODO It should only be necessary to upload the data if something has changed.
+  // In the parallel case however (ParaView with IceT), the solution below causes
+  // data not to be uploaded at all (leading to empty images). Because of this, data
+  // is uploaded on every render pass.
+  //
+  //if (info && info->Has(vtkValuePass::RELOAD_DATA()))
+  if (info)
     {
     int cellFlag = 0;
     typedef vtkValuePass vp;
     this->ValuePassArray = vtkAbstractMapper::GetScalars(input,
       info->Get(vp::SCALAR_MODE()), info->Get(vp::ARRAY_MODE()),
       info->Get(vp::ARRAY_ID()), info->Get(vp::ARRAY_NAME()), cellFlag);
+
     if (!this->ValuePassArray)
       {
       vtkErrorMacro("Invalid data array from GetScalars()!");
@@ -64,10 +132,27 @@ void vtkValuePassHelper::UploadValueData(vtkActor* actor, vtkDataSet* input)
       }
 
     // Upload array data
-    this->ValueBuffer->Upload(&(this->Buffer.front()), numTuples,
-      vtkOpenGLBufferObject::ArrayBuffer);
+    if (this->CurrentDataArrayMode == VTK_SCALAR_MODE_USE_POINT_FIELD_DATA)
+      {
+      // Point data
+      this->ValueBuffer->Upload(&(this->Buffer.front()), static_cast<size_t>(numTuples),
+        vtkOpenGLBufferObject::ArrayBuffer);
+      }
+    else
+      {
+      // Cell data
+      this->CellFloatBuffer->Upload(&(this->Buffer.front()), numTuples,
+        vtkOpenGLBufferObject::TextureBuffer);
 
-    //this->ValueBufferTime.Modified();
+      this->CellFloatTexture->CreateTextureBuffer(static_cast<unsigned int>(numTuples),
+        1, VTK_FLOAT, this->CellFloatBuffer);
+      }
+    }
+
+  // Bind textures
+  if (this->CurrentDataArrayMode == VTK_SCALAR_MODE_USE_CELL_FIELD_DATA)
+    {
+    this->CellFloatTexture->Activate();
     }
 }
 
@@ -85,10 +170,17 @@ void vtkValuePassHelper::UpdateConfiguration(vtkRenderer* ren, vtkActor* act,
   // Configure the mapper's behavior if the ValuePass is active.
   if (this->RenderingMode > 0)
     {
+    vtkInformation *info = act->GetPropertyKeys();
+    if (info)
+      {
+      // Since it has RENDER_VALUES it is assumed it has all the tags from ValuePass
+      this->CurrentDataArrayMode = info->Get(vtkValuePass::SCALAR_MODE());
+      }
+
     switch (this->RenderingMode)
       {
       case vtkValuePass::FLOATING_POINT:
-        this->AllocateBuffer(ren);
+        this->AllocateGraphicsResources(ren);
         break;
 
       case vtkValuePass::INVERTIBLE_LUT:
@@ -107,41 +199,32 @@ void vtkValuePassHelper::UpdateConfiguration(vtkRenderer* ren, vtkActor* act,
     }
   else
     {
-    this->ReleaseBuffer(ren);
+    this->ReleaseGraphicsResources(ren->GetRenderWindow());
     mapper->ClearInvertibleColor();
     }
 }
 
 //-----------------------------------------------------------------------------
-void vtkValuePassHelper::AllocateBuffer(vtkRenderer* ren)
+void vtkValuePassHelper::AllocateGraphicsResources(vtkRenderer* ren)
 {
-  if (this->ValueBuffer)
+  if (this->ResourcesAllocated)
+    {
     return;
+    }
 
+  // For point data
   this->ValueBuffer = vtkOpenGLBufferObject::New();
   this->ValueBuffer->SetType(vtkOpenGLBufferObject::ArrayBuffer);
-}
-
-//-----------------------------------------------------------------------------
-void vtkValuePassHelper::ReleaseBuffer(vtkRenderer* ren)
-{
-  if (!this->ValueBuffer)
-    return;
 
-  vtkRenderWindow* renWin = ren->GetRenderWindow();
-  vtkOpenGLRenderWindow* glWin = static_cast<vtkOpenGLRenderWindow*>(renWin);
-  glWin->MakeCurrent();
+  // For cell data
+  this->CellFloatTexture = vtkTextureObject::New();
+  this->CellFloatTexture->SetContext
+    (static_cast<vtkOpenGLRenderWindow*>(ren->GetVTKWindow()));
 
-  // Cleanup GL buffer
-  if (this->ValueBuffer)
-    {
-    this->ValueBuffer->ReleaseGraphicsResources();
-    this->ValueBuffer->Delete();
-    this->ValueBuffer = NULL;
-    vtkOpenGLCheckErrorMacro("Failed to release ValueBuffer resources.");
-    }
+  this->CellFloatBuffer = vtkOpenGLBufferObject::New();
+  this->CellFloatBuffer->SetType(vtkOpenGLBufferObject::TextureBuffer);
 
-  this->ValuePassArray = NULL;
+  this->ResourcesAllocated = true;
 }
 
 //-----------------------------------------------------------------------------
@@ -151,7 +234,9 @@ void vtkValuePassHelper::UpdateShaders(std::string & VSSource, std::string & FSS
   // Pass the value pass attribute to the fragment shader.
   vtkShaderProgram::Substitute(VSSource, "//VTK::ValuePass::Dec",
     "attribute float dataAttribute;\n"
-    "varying float dataValue;\n");
+    "varying float dataValue;\n"
+    "uniform samplerBuffer textureF;\n"
+    );
 
   vtkShaderProgram::Substitute(VSSource, "//VTK::ValuePass::Impl",
     " dataValue = dataAttribute;\n");
@@ -160,32 +245,76 @@ void vtkValuePassHelper::UpdateShaders(std::string & VSSource, std::string & FSS
   // other sections of the fragment shader, so they are included for it to build
   // correctly).
   vtkShaderProgram::Substitute(FSSource, "//VTK::ValuePass::Dec",
-    "varying float dataValue;\n");
+    "varying float dataValue;\n"
+    "uniform samplerBuffer textureF;\n");
+
+  if (this->CurrentDataArrayMode == VTK_SCALAR_MODE_USE_POINT_FIELD_DATA)
+    {
+    required += std::string
+      (
+       "  vec4 texColor = vec4(vec3(dataValue), 1.0);\n"
+       "  gl_FragData[0] = texColor;\n"
+       "  // Return right away since vtkValuePass::FLOATING_POINT mode is enabled\n"
+       "  return;"
+       );
+    }
+  else
+    {
+    required += std::string
+      (
+       "  gl_FragData[0] = texelFetchBuffer(textureF, gl_PrimitiveID + PrimitiveIDOffset);\n"
+
+       "  // Return right away since vtkValuePass::FLOATING_POINT mode is enabled\n"
+       "  return;"
+       );
+    }
 
-  required += std::string(
-    "  vec4 texColor = vec4(vec3(dataValue), 1.0);\n"
-    "  gl_FragData[0] = texColor;\n"
-    "  // Return right away since vtkValuePass::FLOATING_POINT mode is enabled\n"
-    "  return;");
   vtkShaderProgram::Substitute(FSSource, "//VTK::Color::Impl", required);
 }
 
 //-----------------------------------------------------------------------------
-void vtkValuePassHelper::BindValueBuffer(vtkOpenGLHelper& cellBO)
+void vtkValuePassHelper::BindAttributes(vtkOpenGLHelper& cellBO)
 {
-  if (this->ValuePassArray)
+  if (this->CurrentDataArrayMode == VTK_SCALAR_MODE_USE_POINT_FIELD_DATA)
     {
-    if (cellBO.Program->IsAttributeUsed("dataAttribute"))
+    if (this->ValuePassArray)
       {
-      int const elementType = this->ValuePassArray->GetDataType();
-      size_t const stride = sizeof(float);
-
-      if (!cellBO.VAO->AddAttributeArray(cellBO.Program, this->ValueBuffer,
-        "dataAttribute", 0, stride, VTK_FLOAT, 1, false))
+      if (cellBO.Program->IsAttributeUsed("dataAttribute"))
         {
-        vtkErrorMacro(<< "Error setting 'dataAttribute' in shader VAO.");
+        size_t const stride = sizeof(float);
+
+        if (!cellBO.VAO->AddAttributeArray(cellBO.Program, this->ValueBuffer,
+          "dataAttribute", 0, stride, VTK_FLOAT, 1, false))
+          {
+          vtkErrorMacro(<< "Error setting 'dataAttribute' in shader VAO.");
+          }
         }
       }
     }
-  vtkOpenGLCheckErrorMacro("Failed in SetupValueBuffer!");
+}
+
+//-----------------------------------------------------------------------------
+void vtkValuePassHelper::BindUniforms(vtkOpenGLHelper& cellBO)
+{
+  if (this->CurrentDataArrayMode == VTK_SCALAR_MODE_USE_CELL_FIELD_DATA)
+    {
+    if (cellBO.Program->IsAttributeUsed("textureF"))
+      {
+      int tunit = this->CellFloatTexture->GetTextureUnit();
+      cellBO.Program->SetUniformi("textureF", tunit);
+      }
+    }
+}
+
+//-----------------------------------------------------------------------------
+bool vtkValuePassHelper::RequiresShaderRebuild(vtkActor* act)
+{
+  if (this->RenderingMode == vtkValuePass::FLOATING_POINT &&
+   this->CurrentDataArrayMode != this->LastDataArrayMode)
+    {
+    this->LastDataArrayMode = this->CurrentDataArrayMode;
+    return true;
+    }
+
+  return false;
 }
diff --git a/Rendering/OpenGL2/vtkValuePassHelper.h b/Rendering/OpenGL2/vtkValuePassHelper.h
index b49b184e263..14ed1c87162 100644
--- a/Rendering/OpenGL2/vtkValuePassHelper.h
+++ b/Rendering/OpenGL2/vtkValuePassHelper.h
@@ -4,16 +4,17 @@
 #include "vtkRenderingOpenGL2Module.h"
 
 
-class vtkOpenGLBufferObject;
-//class vtkTimeStamp;
-class vtkDataArray;
-class vtkRenderer;
 class vtkActor;
+class vtkDataArray;
 class vtkDataSet;
-class vtkOpenGLHelper;
 class vtkFloatArray;
 class vtkMapper;
-
+class vtkOpenGLBufferObject;
+class vtkOpenGLHelper;
+class vtkRenderer;
+class vtkTextureObject;
+class vtkWindow;
+class vtkValuePass;
 
 class VTKRENDERINGOPENGL2_EXPORT vtkValuePassHelper : public vtkObject
 {
@@ -31,24 +32,32 @@ protected:
   vtkGetMacro(RenderingMode, int);
 
   void UpdateConfiguration(vtkRenderer* ren, vtkActor* act, vtkMapper* mapper);
-  void UploadValueData(vtkActor* actor, vtkDataSet* input);
+  void RenderPieceStart(vtkActor* actor, vtkDataSet* input);
   void UpdateShaders(std::string & VSSource, std::string & FSSource,
     std::string & required);
-  void BindValueBuffer(vtkOpenGLHelper& cellBO);
+  void BindAttributes(vtkOpenGLHelper& cellBO);
+  void BindUniforms(vtkOpenGLHelper& cellBO);
+  void ReleaseGraphicsResources(vtkWindow* win);
+  void RenderPieceFinish();
+  bool RequiresShaderRebuild(vtkActor* actor);
 
 private:
 
+  void AllocateGraphicsResources(vtkRenderer* ren);
+
   vtkValuePassHelper(const vtkValuePassHelper &); // Not implemented.
   void operator=(const vtkValuePassHelper &); // Not implemented.
 
-  void AllocateBuffer(vtkRenderer* ren);
-  void ReleaseBuffer(vtkRenderer* ren);
-
 ////////////////////////////////////////////////////////////////////////////////
 
-  //vtkTimeStamp ValueBufferTime;
   vtkOpenGLBufferObject* ValueBuffer;
   vtkDataArray* ValuePassArray;
   std::vector<float> Buffer;
+  int CurrentDataArrayMode;
+  int LastDataArrayMode;
   int RenderingMode;
+  bool ResourcesAllocated;
+
+  vtkTextureObject* CellFloatTexture;
+  vtkOpenGLBufferObject* CellFloatBuffer;
 };
-- 
GitLab