/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkFixedPointVolumeRayCastMIPHelper.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkFixedPointVolumeRayCastMIPHelper.h"

#include "vtkCommand.h"
#include "vtkDataArray.h"
#include "vtkFixedPointRayCastImage.h"
#include "vtkFixedPointVolumeRayCastMapper.h"
#include "vtkImageData.h"
#include "vtkObjectFactory.h"
#include "vtkRenderWindow.h"
#include "vtkVolume.h"
#include "vtkVolumeProperty.h"

#include <cmath>

vtkStandardNewMacro(vtkFixedPointVolumeRayCastMIPHelper);

// Construct a new vtkFixedPointVolumeRayCastMIPHelper with default values
vtkFixedPointVolumeRayCastMIPHelper::vtkFixedPointVolumeRayCastMIPHelper() = default;

// Destruct a vtkFixedPointVolumeRayCastMIPHelper - clean up any memory used
vtkFixedPointVolumeRayCastMIPHelper::~vtkFixedPointVolumeRayCastMIPHelper() = default;

// This method is called when the interpolation type is nearest neighbor and
// the data contains one component. In the inner loop we will compute the
// maximum value (in native type). After we have a maximum value for the ray
// we will convert it to unsigned short using the scale/shift, then use this
// index to lookup the final color/opacity.
template <class T>
void vtkFixedPointMIPHelperGenerateImageOneNN( T *data,
                                       int threadID,
                                       int threadCount,
                                       vtkFixedPointVolumeRayCastMapper *mapper,
                                       vtkVolume *vtkNotUsed(vol))
{
  VTKKWRCHelper_InitializationAndLoopStartNN();
  VTKKWRCHelper_InitializeMIPOneNN();
  VTKKWRCHelper_SpaceLeapSetup();

  if ( cropping )
  {
    int maxValueDefined = 0;
    unsigned short maxIdx = 0;

    for ( k = 0; k < numSteps; k++ )
    {
      if ( k )
      {
        mapper->FixedPointIncrement( pos, dir );
      }

      VTKKWRCHelper_MIPSpaceLeapCheck( maxIdx, maxValueDefined, mapper->GetFlipMIPComparison() );

      if ( !mapper->CheckIfCropped( pos ) )
      {
        mapper->ShiftVectorDown( pos, spos );
        dptr = data +  spos[0]*inc[0] + spos[1]*inc[1] + spos[2]*inc[2];
        if ( !maxValueDefined ||
             ( (mapper->GetFlipMIPComparison() && *dptr < maxValue) ||
               (!mapper->GetFlipMIPComparison() && *dptr > maxValue) ) )
        {
          maxValue = *dptr;
          maxIdx = static_cast<unsigned short>((maxValue + shift[0])*scale[0]);
          maxValueDefined = 1;
        }
      }
    }

    if ( maxValueDefined )
    {
      VTKKWRCHelper_LookupColorMax( colorTable[0], scalarOpacityTable[0], maxIdx, imagePtr );
    }
    else
    {
      imagePtr[0] = imagePtr[1] = imagePtr[2] = imagePtr[3] = 0;
    }
  }
  else
  {
    unsigned short maxIdx =
      static_cast<unsigned short>((maxValue + shift[0])*scale[0]);

    for ( k = 0; k < numSteps; k++ )
    {
      if ( k )
      {
        mapper->FixedPointIncrement( pos, dir );
      }

      VTKKWRCHelper_MIPSpaceLeapCheck( maxIdx, 1, mapper->GetFlipMIPComparison() );

      mapper->ShiftVectorDown( pos, spos );
      dptr = data +  spos[0]*inc[0] + spos[1]*inc[1] + spos[2]*inc[2];
      if ( mapper->GetFlipMIPComparison() )
      {
        maxValue = ( *dptr < maxValue )?(*dptr):(maxValue);
      }
      else
      {
        maxValue = ( *dptr > maxValue )?(*dptr):(maxValue);
      }

      maxIdx = static_cast<unsigned short>((maxValue + shift[0])*scale[0]);
    }

    VTKKWRCHelper_LookupColorMax( colorTable[0], scalarOpacityTable[0], maxIdx, imagePtr );
  }

  VTKKWRCHelper_IncrementAndLoopEnd();

}

// This method is called when the interpolation type is nearest neighbor and
// the data has two or four dependent components. If it is four, they must be
// unsigned char components.  Compute max of last components in native type,
// then use first component to look up a color (2 component data) or first three
// as the color directly (four component data). Lookup alpha off the last component.
template <class T>
void vtkFixedPointMIPHelperGenerateImageDependentNN(
  T *data,
  int threadID,
  int threadCount,
  vtkFixedPointVolumeRayCastMapper *mapper,
  vtkVolume *vtkNotUsed(vol))
{
  VTKKWRCHelper_InitializationAndLoopStartNN();
  VTKKWRCHelper_InitializeMIPMultiNN();
  VTKKWRCHelper_SpaceLeapSetup();

  int maxValueDefined = 0;
  unsigned short maxIdxS = 0;

  for ( k = 0; k < numSteps; k++ )
  {
    if ( k )
    {
      mapper->FixedPointIncrement( pos, dir );
    }

    VTKKWRCHelper_MIPSpaceLeapCheck( maxIdxS, maxValueDefined,
                                     mapper->GetFlipMIPComparison() );
    VTKKWRCHelper_CroppingCheckNN( pos );

    mapper->ShiftVectorDown( pos, spos );
    dptr = data +  spos[0]*inc[0] + spos[1]*inc[1] + spos[2]*inc[2];
    if ( !maxValueDefined ||
         ( ( mapper->GetFlipMIPComparison() && *(dptr + components - 1) < maxValue[components-1] ) ||
           ( !mapper->GetFlipMIPComparison() && *(dptr + components - 1) > maxValue[components-1] ) ) )
    {
      for ( c = 0; c < components; c++ )
      {
        maxValue[c] = *(dptr+c);
      }
      maxIdxS =
        static_cast<unsigned short>((maxValue[components-1] +
                                     shift[components-1])*scale[components-1]);
      maxValueDefined = 1;
    }
  }

  if ( maxValueDefined )
  {
    unsigned short maxIdx[4]={0,0,0,0};
    if ( components == 2 )
    {
      maxIdx[0] = static_cast<unsigned short>((maxValue[0] +
                                               shift[0])*scale[0]);
      maxIdx[1] = static_cast<unsigned short>((maxValue[1] +
                                               shift[1])*scale[1]);
    }
    else
    {
      maxIdx[0] = static_cast<unsigned short>(maxValue[0]);
      maxIdx[1] = static_cast<unsigned short>(maxValue[1]);
      maxIdx[2] = static_cast<unsigned short>(maxValue[2]);
      maxIdx[3] = static_cast<unsigned short>((maxValue[3] +
                                               shift[3])*scale[3]);
    }

    for ( c = 0; c < components; c++ )
    {
    }
    VTKKWRCHelper_LookupDependentColorUS( colorTable[0], scalarOpacityTable[0],
                                          maxIdx, components, imagePtr );
  }
  else
  {
    imagePtr[0] = imagePtr[1] = imagePtr[2] = imagePtr[3] = 0;
  }

  VTKKWRCHelper_IncrementAndLoopEnd();
}

// This method is called when the interpolation type is nearest neighbor and
// the data has more than one independent components. We compute the max of
// each component along the ray in native type, then use the scale/shift to
// convert this into an unsigned short index value. We use the index values
// to lookup the color/opacity per component, then use the component weights to
// blend these into one final color.
template <class T>
void vtkFixedPointMIPHelperGenerateImageIndependentNN(
  T *data,
  int threadID,
  int threadCount,
  vtkFixedPointVolumeRayCastMapper *mapper,
  vtkVolume *vol)
{
  VTKKWRCHelper_InitializeWeights();
  VTKKWRCHelper_InitializationAndLoopStartNN();
  VTKKWRCHelper_InitializeMIPMultiNN();
  VTKKWRCHelper_SpaceLeapSetupMulti();

  int maxValueDefined = 0;
  unsigned short maxIdx[4] = {0, 0, 0, 0};

  for ( k = 0; k < numSteps; k++ )
  {
    if ( k )
    {
      mapper->FixedPointIncrement( pos, dir );
    }
    VTKKWRCHelper_CroppingCheckNN( pos );
    VTKKWRCHelper_MIPSpaceLeapPopulateMulti( maxIdx,
                                             mapper->GetFlipMIPComparison() )

    mapper->ShiftVectorDown( pos, spos );
    dptr = data +  spos[0]*inc[0] + spos[1]*inc[1] + spos[2]*inc[2];

    if ( !maxValueDefined )
    {
      for ( c = 0; c < components; c++ )
      {
        maxValue[c] = *(dptr+c);
        maxIdx[c] = static_cast<unsigned short>((maxValue[c] +
                                                 shift[c])*scale[c]);
      }
      maxValueDefined = 1;
    }
    else
    {
      for ( c = 0; c < components; c++ )
      {
        if ( VTKKWRCHelper_MIPSpaceLeapCheckMulti( c, mapper->GetFlipMIPComparison() ) &&
            ((mapper->GetFlipMIPComparison() &&  *(dptr + c) < maxValue[c] ) ||
             (!mapper->GetFlipMIPComparison() &&  *(dptr + c) > maxValue[c] )) )
        {
          maxValue[c] = *(dptr+c);
          maxIdx[c] = static_cast<unsigned short>((maxValue[c] +
                                                   shift[c])*scale[c]);
        }
      }
    }
  }

  imagePtr[0] = imagePtr[1] = imagePtr[2] = imagePtr[3] = 0;
  if ( maxValueDefined )
  {
    VTKKWRCHelper_LookupAndCombineIndependentColorsMax(colorTable,
                                                       scalarOpacityTable,
                                                       maxIdx, weights,
                                                       components, imagePtr );
  }

  VTKKWRCHelper_IncrementAndLoopEnd();
}

// This method is called when the interpolation type is linear, the
// data contains one component and scale = 1.0 and shift = 0.0. This is
// the simple case were we do not need to apply scale/shift in the
// inner loop. In the inner loop we compute the eight cell vertex values
// (if we have changed cells). We compute our weights within the cell
// according to our fractional position within the cell, and apply trilinear
// interpolation to compute the index. We find the maximum index along
// the ray, and then use this to look up a final color.
template <class T>
void vtkFixedPointMIPHelperGenerateImageOneSimpleTrilin(
  T *dataPtr,
  int threadID,
  int threadCount,
  vtkFixedPointVolumeRayCastMapper *mapper,
  vtkVolume *vtkNotUsed(vol))
{
  VTKKWRCHelper_InitializationAndLoopStartTrilin();
  VTKKWRCHelper_InitializeMIPOneTrilin();
  VTKKWRCHelper_SpaceLeapSetup();

  int maxValueDefined = 0;
  unsigned short maxIdx=0;
  unsigned int maxScalar = 0;

  for ( k = 0; k < numSteps; k++ )
  {
    if ( k )
    {
      mapper->FixedPointIncrement( pos, dir );
    }

    VTKKWRCHelper_MIPSpaceLeapCheck( maxIdx, maxValueDefined,
                                     mapper->GetFlipMIPComparison() );
    VTKKWRCHelper_CroppingCheckTrilin( pos );

    mapper->ShiftVectorDown( pos, spos );
    if ( spos[0] != oldSPos[0] ||
         spos[1] != oldSPos[1] ||
         spos[2] != oldSPos[2] )
    {
      oldSPos[0] = spos[0];
      oldSPos[1] = spos[1];
      oldSPos[2] = spos[2];

      dptr = dataPtr + spos[0]*inc[0] + spos[1]*inc[1] + spos[2]*inc[2];
      VTKKWRCHelper_GetCellScalarValuesSimple( dptr );
      if ( mapper->GetFlipMIPComparison() )
      {
        maxScalar = (A<B)?(A):(B);
        maxScalar = (C<maxScalar)?(C):(maxScalar);
        maxScalar = (D<maxScalar)?(D):(maxScalar);
        maxScalar = (E<maxScalar)?(E):(maxScalar);
        maxScalar = (F<maxScalar)?(F):(maxScalar);
        maxScalar = (G<maxScalar)?(G):(maxScalar);
        maxScalar = (H<maxScalar)?(H):(maxScalar);
      }
      else
      {
        maxScalar = (A>B)?(A):(B);
        maxScalar = (C>maxScalar)?(C):(maxScalar);
        maxScalar = (D>maxScalar)?(D):(maxScalar);
        maxScalar = (E>maxScalar)?(E):(maxScalar);
        maxScalar = (F>maxScalar)?(F):(maxScalar);
        maxScalar = (G>maxScalar)?(G):(maxScalar);
        maxScalar = (H>maxScalar)?(H):(maxScalar);
      }

    }

    if ( !maxValueDefined ||
         ((mapper->GetFlipMIPComparison() && maxScalar < static_cast<unsigned int>(maxValue) ) ||
          (!mapper->GetFlipMIPComparison() && maxScalar > static_cast<unsigned int>(maxValue) )) )
    {
      VTKKWRCHelper_ComputeWeights(pos);
      VTKKWRCHelper_InterpolateScalar(val);

      if ( !maxValueDefined ||
           ((mapper->GetFlipMIPComparison() && val < maxValue ) ||
            (!mapper->GetFlipMIPComparison() && val > maxValue )) )
      {
        maxValue = val;
        maxIdx = static_cast<unsigned short>(maxValue);
        maxValueDefined = 1;
      }
    }
  }

  if ( maxValueDefined )
  {
    VTKKWRCHelper_LookupColorMax( colorTable[0], scalarOpacityTable[0], maxIdx, imagePtr );
  }
  else
  {
    imagePtr[0] = imagePtr[1] = imagePtr[2] = imagePtr[3] = 0;
  }

  VTKKWRCHelper_IncrementAndLoopEnd();
}


// This method is called when the interpolation type is linear, the
// data contains one component and scale != 1.0 or shift != 0.0. This
// means that we need to apply scale/shift in the inner loop to compute
// an unsigned short index value. In the inner loop we compute the eight cell
// vertex values (as unsigned short indices, if we have changed cells). We
// compute our weights within the cell according to our fractional position
// within the cell, and apply trilinear interpolation to compute the index.
// We find the maximum index along the ray, and then use this to look up a
// final color.
template <class T>
void vtkFixedPointMIPHelperGenerateImageOneTrilin(
  T *dataPtr,
  int threadID,
  int threadCount,
  vtkFixedPointVolumeRayCastMapper *mapper,
  vtkVolume *vtkNotUsed(vol))
{
  VTKKWRCHelper_InitializationAndLoopStartTrilin();
  VTKKWRCHelper_InitializeMIPOneTrilin();
  VTKKWRCHelper_SpaceLeapSetup();

  int maxValueDefined = 0;
  unsigned short maxIdx = 0;
  for ( k = 0; k < numSteps; k++ )
  {
    if ( k )
    {
      mapper->FixedPointIncrement( pos, dir );
    }

    VTKKWRCHelper_CroppingCheckTrilin( pos );
    VTKKWRCHelper_MIPSpaceLeapCheck( maxIdx, maxValueDefined,
                                     mapper->GetFlipMIPComparison() );

    mapper->ShiftVectorDown( pos, spos );
    if ( spos[0] != oldSPos[0] ||
         spos[1] != oldSPos[1] ||
         spos[2] != oldSPos[2] )
    {
      oldSPos[0] = spos[0];
      oldSPos[1] = spos[1];
      oldSPos[2] = spos[2];


      dptr = dataPtr + spos[0]*inc[0] + spos[1]*inc[1] + spos[2]*inc[2];
      VTKKWRCHelper_GetCellScalarValues( dptr, scale[0], shift[0] );
    }

    VTKKWRCHelper_ComputeWeights(pos);
    VTKKWRCHelper_InterpolateScalar(val);

    if ( !maxValueDefined ||
         ((mapper->GetFlipMIPComparison() && val < maxValue ) ||
          (!mapper->GetFlipMIPComparison() && val > maxValue )) )
    {
      maxValue = val;
      maxIdx = static_cast<unsigned short>(maxValue);
      maxValueDefined = 1;
    }
  }

  if ( maxValueDefined )
  {
    VTKKWRCHelper_LookupColorMax( colorTable[0], scalarOpacityTable[0],
                                  maxIdx, imagePtr );
  }
  else
  {
    imagePtr[0] = imagePtr[1] = imagePtr[2] = imagePtr[3] = 0;
  }

  VTKKWRCHelper_IncrementAndLoopEnd();
}

// This method is used when the interpolation type is linear, the data has
// two or four components and the components are not considered independent.
// For four component d>>(VTKKW_FP_SHIFT - 8));ata, the data must be unsigned char in type. In the
// inner loop we get the data value for the eight cell corners (if we have
// changed cells) for all components as unsigned shorts (we use the
// scale/shift to ensure the correct range). We compute our weights within
// the cell according to our fractional position within the cell, and apply
// trilinear interpolation to compute the index values. For two component data,
// We use the first index to lookup a color and the second to look up an opacity
// for this sample. For four component data we use the first three components
// directly as a color, then we look up the opacity using the fourth component.
// We then composite this into the color computed so far along the ray, and
// check if we can terminate at this point (if the accumulated opacity is
// higher than some threshold).
template <class T>
void vtkFixedPointMIPHelperGenerateImageDependentTrilin(
  T *dataPtr,
  int threadID,
  int threadCount,
  vtkFixedPointVolumeRayCastMapper *mapper,
  vtkVolume *vtkNotUsed(vol))
{
  VTKKWRCHelper_InitializationAndLoopStartTrilin();
  VTKKWRCHelper_InitializeMIPMultiTrilin();
  VTKKWRCHelper_SpaceLeapSetup();

  int maxValueDefined = 0;
  unsigned short maxIdx = 0;
  for ( k = 0; k < numSteps; k++ )
  {
    if ( k )
    {
      mapper->FixedPointIncrement( pos, dir );
    }

    VTKKWRCHelper_CroppingCheckTrilin( pos );
    VTKKWRCHelper_MIPSpaceLeapCheck( maxIdx, maxValueDefined,
                                     mapper->GetFlipMIPComparison() );

    mapper->ShiftVectorDown( pos, spos );
    if ( spos[0] != oldSPos[0] ||
         spos[1] != oldSPos[1] ||
         spos[2] != oldSPos[2] )
    {
      oldSPos[0] = spos[0];
      oldSPos[1] = spos[1];
      oldSPos[2] = spos[2];

      if ( components == 2 )
      {
        for ( c= 0; c < components; c++ )
        {
          dptr = dataPtr + spos[0]*inc[0] + spos[1]*inc[1] + spos[2]*inc[2]+ c;
          VTKKWRCHelper_GetCellComponentScalarValues( dptr, c, scale[c],
                                                      shift[c] );
        }
      }
      else
      {
        for ( c= 0; c < 3; c++ )
        {
          dptr = dataPtr + spos[0]*inc[0] + spos[1]*inc[1] + spos[2]*inc[2]+ c;
          VTKKWRCHelper_GetCellComponentRawScalarValues( dptr, c );
        }
        dptr = dataPtr + spos[0]*inc[0] + spos[1]*inc[1] + spos[2]*inc[2] + c;
        VTKKWRCHelper_GetCellComponentScalarValues( dptr,3,scale[3],shift[3] );
      }

    }

    VTKKWRCHelper_ComputeWeights(pos);
    VTKKWRCHelper_InterpolateScalarComponent( val, c, components );

    if ( !maxValueDefined ||
         ((mapper->GetFlipMIPComparison() && (val[components-1] < maxValue[components-1]) ) ||
          (!mapper->GetFlipMIPComparison() && (val[components-1] > maxValue[components-1]) )) )
    {
      for ( c= 0; c < components; c++ )
      {
        maxValue[c] = val[c];
      }
      maxIdx = static_cast<unsigned short>((maxValue[components-1] +
                                            shift[components-1])*scale[components-1]);
      maxValueDefined = 1;
    }
  }

  if ( maxValueDefined )
  {
    VTKKWRCHelper_LookupDependentColorUS( colorTable[0],
                                          scalarOpacityTable[0],
                                          maxValue, components, imagePtr );
  }
  else
  {
    imagePtr[0] = imagePtr[1] = imagePtr[2] = imagePtr[3] = 0;
  }

  VTKKWRCHelper_IncrementAndLoopEnd();
}

// This method is used when the interpolation type is linear, the data has
// more than one component and the components are considered independent. In
// the inner loop we get the data value for the eight cell corners (if we have
// changed cells) for all components as an unsigned shorts (we have to use the
// scale/shift to ensure that we obtained unsigned short indices) We compute
// our weights within the cell according to our fractional position within the
// cell, and apply trilinear interpolation to compute a value for each
// component. We do this for each sample along the ray to find a maximum value
// per component, then we look up a color/opacity for each component and blend
// them according to the component weights.
template <class T>
void vtkFixedPointMIPHelperGenerateImageIndependentTrilin(
  T *dataPtr,
  int threadID,
  int threadCount,
  vtkFixedPointVolumeRayCastMapper *mapper,
  vtkVolume *vol)
{
  VTKKWRCHelper_InitializeWeights();
  VTKKWRCHelper_InitializationAndLoopStartTrilin();
  VTKKWRCHelper_InitializeMIPMultiTrilin();

  int maxValueDefined = 0;
  for ( k = 0; k < numSteps; k++ )
  {
    if ( k )
    {
      mapper->FixedPointIncrement( pos, dir );
    }

    VTKKWRCHelper_CroppingCheckTrilin( pos );

    mapper->ShiftVectorDown( pos, spos );
    if ( spos[0] != oldSPos[0] ||
         spos[1] != oldSPos[1] ||
         spos[2] != oldSPos[2] )
    {
      oldSPos[0] = spos[0];
      oldSPos[1] = spos[1];
      oldSPos[2] = spos[2];

      for ( c= 0; c < components; c++ )
      {
        dptr = dataPtr + spos[0]*inc[0] + spos[1]*inc[1] + spos[2]*inc[2] + c;
        VTKKWRCHelper_GetCellComponentScalarValues( dptr, c, scale[c],
                                                    shift[c] );
      }
    }

    VTKKWRCHelper_ComputeWeights(pos);
    VTKKWRCHelper_InterpolateScalarComponent( val, c, components );

    if ( !maxValueDefined )
    {
      for ( c= 0; c < components; c++ )
      {
        maxValue[c] = val[c];
      }
      maxValueDefined = 1;
    }
    else
    {
      for ( c= 0; c < components; c++ )
      {
        if ( ( mapper->GetFlipMIPComparison() && val[c] < maxValue[c] ) ||
             ( !mapper->GetFlipMIPComparison() && val[c] > maxValue[c] ) )
        {
          maxValue[c] = val[c];
        }
      }
    }
  }

  imagePtr[0] = imagePtr[1] = imagePtr[2] = imagePtr[3] = 0;
  if ( maxValueDefined )
  {
    VTKKWRCHelper_LookupAndCombineIndependentColorsMax( colorTable,
                                                        scalarOpacityTable,
                                                        maxValue, weights,
                                                        components, imagePtr );
  }

  VTKKWRCHelper_IncrementAndLoopEnd();
}

void vtkFixedPointVolumeRayCastMIPHelper::GenerateImage(
  int threadID,
  int threadCount,
  vtkVolume *vol,
  vtkFixedPointVolumeRayCastMapper *mapper )
{
  void *dataPtr  = mapper->GetCurrentScalars()->GetVoidPointer(0);
  int scalarType = mapper->GetCurrentScalars()->GetDataType();

  // Nearest Neighbor interpolate
  if ( mapper->ShouldUseNearestNeighborInterpolation( vol ) )
  {
    // One component data
    if ( mapper->GetCurrentScalars()->GetNumberOfComponents() == 1 )
    {
      switch ( scalarType )
      {
        vtkTemplateMacro(
          vtkFixedPointMIPHelperGenerateImageOneNN(
            static_cast<VTK_TT *>(dataPtr),
            threadID, threadCount, mapper, vol) );
      }
    }
    // More that one independent components
    else if ( vol->GetProperty()->GetIndependentComponents() )
    {
      switch ( scalarType )
      {
        vtkTemplateMacro(
          vtkFixedPointMIPHelperGenerateImageIndependentNN(
            static_cast<VTK_TT *>(dataPtr),
            threadID, threadCount, mapper, vol) );
      }
    }
    // Dependent (color) components
    else
    {
      switch ( scalarType )
      {
        vtkTemplateMacro(
          vtkFixedPointMIPHelperGenerateImageDependentNN(
            static_cast<VTK_TT *>(dataPtr),
            threadID, threadCount, mapper, vol) );
      }
    }
  }
  // Trilinear Interpolation
  else
  {
    // One component
    if ( mapper->GetCurrentScalars()->GetNumberOfComponents() == 1 )
    {
      // Scale == 1.0 and shift == 0.0 - simple case (faster)
      if ( mapper->GetTableScale()[0] == 1.0 &&
           mapper->GetTableShift()[0] == 0.0 )
      {
        switch ( scalarType )
        {
          vtkTemplateMacro(
            vtkFixedPointMIPHelperGenerateImageOneSimpleTrilin(
              static_cast<VTK_TT *>(dataPtr),
              threadID, threadCount, mapper, vol) );
        }
      }
      // Scale != 1.0 or shift != 0.0 - must apply scale/shift in inner loop
      else
      {
        switch ( scalarType )
        {
          vtkTemplateMacro(
            vtkFixedPointMIPHelperGenerateImageOneTrilin(
              static_cast<VTK_TT *>(dataPtr),
              threadID, threadCount, mapper, vol) );
        }
      }
    }
    // Independent components (more than one)
    else if ( vol->GetProperty()->GetIndependentComponents() )
    {
      switch ( scalarType )
      {
        vtkTemplateMacro(
          vtkFixedPointMIPHelperGenerateImageIndependentTrilin(
            static_cast<VTK_TT *>(dataPtr),
            threadID, threadCount, mapper, vol) );
      }
    }
    // Dependent components
    else
    {
      switch ( scalarType )
      {
        vtkTemplateMacro(
          vtkFixedPointMIPHelperGenerateImageDependentTrilin(
            static_cast<VTK_TT *>(dataPtr),
            threadID, threadCount, mapper, vol) );
      }
    }
  }
}

// Print method for vtkFixedPointVolumeRayCastMIPHelper
void vtkFixedPointVolumeRayCastMIPHelper::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}


