text: /*=========================================================================
  
    Program:   Visualization Toolkit
    Module:    vtkGPUVolumeRayCastMapper.h
  
    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.
  
  =========================================================================*/
  /**
   * @class   vtkGPUVolumeRayCastMapper
   * @brief   Ray casting performed on the GPU.
   *
   * vtkGPUVolumeRayCastMapper is a volume mapper that performs ray casting on
   * the GPU using fragment programs.
   *
   * This mapper supports connections in multiple ports of input 0 (port 0 being
   * the only required connection). It is up to the concrete implementation
   * whether additional inputs will be used during rendering. This class maintains
   * a list of the currently active input ports (Ports) as well as a list of the
   * ports that have been disconnected (RemovedPorts). RemovedPorts is used the
   * the concrete implementation to clean up internal structures.
   *
   */
  #ifndef vtkGPUVolumeRayCastMapper_h
  #define vtkGPUVolumeRayCastMapper_h
  #include <unordered_map> // For std::unordered_map
  #include <vector>        // For std::vector
  
  #include "vtkRenderingVolumeModule.h" // For export macro
  #include "vtkVolumeMapper.h"
  
  class vtkContourValues;
  class vtkRenderWindow;
  class vtkVolumeProperty;
  
  class VTKRENDERINGVOLUME_EXPORT vtkGPUVolumeRayCastMapper : public vtkVolumeMapper
  {
  public:
    static vtkGPUVolumeRayCastMapper* New();
    vtkTypeMacro(vtkGPUVolumeRayCastMapper, vtkVolumeMapper);
    void PrintSelf(ostream& os, vtkIndent indent) override;
  
    ///@{
    /**
     * If AutoAdjustSampleDistances is on, the ImageSampleDistance
     * will be varied to achieve the allocated render time of this
     * prop (controlled by the desired update rate and any culling in
     * use).
     */
    vtkSetClampMacro(AutoAdjustSampleDistances, vtkTypeBool, 0, 1);
    vtkGetMacro(AutoAdjustSampleDistances, vtkTypeBool);
    vtkBooleanMacro(AutoAdjustSampleDistances, vtkTypeBool);
    ///@}
  
    ///@{
    /**
     * Compute the sample distance from the data spacing.  When the number of
     * voxels is 8, the sample distance will be roughly 1/200 the average voxel
     * size. The distance will grow proportionally to numVoxels^(1/3). Off by default.
     */
    vtkSetClampMacro(LockSampleDistanceToInputSpacing, vtkTypeBool, 0, 1);
    vtkGetMacro(LockSampleDistanceToInputSpacing, vtkTypeBool);
    vtkBooleanMacro(LockSampleDistanceToInputSpacing, vtkTypeBool);
    ///@}
  
    ///@{
    /**
     * If UseJittering is on, each ray traversal direction will be
     * perturbed slightly using a noise-texture to get rid of wood-grain
     * effect.
     */
    vtkSetClampMacro(UseJittering, vtkTypeBool, 0, 1);
    vtkGetMacro(UseJittering, vtkTypeBool);
    vtkBooleanMacro(UseJittering, vtkTypeBool);
    ///@}
  
    ///@{
    /**
     * If UseDepthPass is on, the mapper will use two passes. In the first
     * pass, an isocontour depth buffer will be utilized as starting point
     * for ray-casting hence eliminating traversal on voxels that are
     * not going to participate in final rendering. UseDepthPass requires
     * reasonable contour values to be set which can be set by calling
     * GetDepthPassContourValues() method and using vtkControurValues API.
     */
    vtkSetClampMacro(UseDepthPass, vtkTypeBool, 0, 1);
    vtkGetMacro(UseDepthPass, vtkTypeBool);
    vtkBooleanMacro(UseDepthPass, vtkTypeBool);
    ///@}
  
    /**
     * Return handle to contour values container so
     * that values can be set by the application. Contour values
     * will be used only when UseDepthPass is on.
     */
    vtkContourValues* GetDepthPassContourValues();
  
    ///@{
    /**
     * Set/Get the distance between samples used for rendering
     * when AutoAdjustSampleDistances is off, or when this mapper
     * has more than 1 second allocated to it for rendering.
     * Initial value is 1.0.
     */
    vtkSetMacro(SampleDistance, float);
    vtkGetMacro(SampleDistance, float);
    ///@}
  
    ///@{
    /**
     * Sampling distance in the XY image dimensions. Default value of 1 meaning
     * 1 ray cast per pixel. If set to 0.5, 4 rays will be cast per pixel. If
     * set to 2.0, 1 ray will be cast for every 4 (2 by 2) pixels. This value
     * will be adjusted to meet a desired frame rate when AutoAdjustSampleDistances
     * is on.
     */
    vtkSetClampMacro(ImageSampleDistance, float, 0.1f, 100.0f);
    vtkGetMacro(ImageSampleDistance, float);
    ///@}
  
    ///@{
    /**
     * This is the minimum image sample distance allow when the image
     * sample distance is being automatically adjusted.
     */
    vtkSetClampMacro(MinimumImageSampleDistance, float, 0.1f, 100.0f);
    vtkGetMacro(MinimumImageSampleDistance, float);
    ///@}
  
    ///@{
    /**
     * This is the maximum image sample distance allow when the image
     * sample distance is being automatically adjusted.
     */
    vtkSetClampMacro(MaximumImageSampleDistance, float, 0.1f, 100.0f);
    vtkGetMacro(MaximumImageSampleDistance, float);
    ///@}
  
    ///@{
    /**
     * Set/Get the window / level applied to the final color.
     * This allows brightness / contrast adjustments on the
     * final image.
     * window is the width of the window.
     * level is the center of the window.
     * Initial window value is 1.0
     * Initial level value is 0.5
     * window cannot be null but can be negative, this way
     * values will be reversed.
     * |window| can be larger than 1.0
     * level can be any real value.
     */
    vtkSetMacro(FinalColorWindow, float);
    vtkGetMacro(FinalColorWindow, float);
    vtkSetMacro(FinalColorLevel, float);
    vtkGetMacro(FinalColorLevel, float);
    ///@}
  
    ///@{
    /**
     * Maximum size of the 3D texture in GPU memory.
     * Will default to the size computed from the graphics
     * card. Can be adjusted by the user.
     */
    vtkSetMacro(MaxMemoryInBytes, vtkIdType);
    vtkGetMacro(MaxMemoryInBytes, vtkIdType);
    ///@}
  
    ///@{
    /**
     * Maximum fraction of the MaxMemoryInBytes that should
     * be used to hold the texture. Valid values are 0.1 to
     * 1.0.
     */
    vtkSetClampMacro(MaxMemoryFraction, float, 0.1f, 1.0f);
    vtkGetMacro(MaxMemoryFraction, float);
    ///@}
  
    ///@{
    /**
     * Tells if the mapper will report intermediate progress.
     * Initial value is true. As the progress works with a GL blocking
     * call (glFinish()), this can be useful for huge dataset but can
     * slow down rendering of small dataset. It should be set to true
     * for big dataset or complex shading and streaming but to false for
     * small datasets.
     */
    vtkSetMacro(ReportProgress, bool);
    vtkGetMacro(ReportProgress, bool);
    ///@}
  
    /**
     * Based on hardware and properties, we may or may not be able to
     * render using 3D texture mapping. This indicates if 3D texture
     * mapping is supported by the hardware, and if the other extensions
     * necessary to support the specific properties are available.
     */
    virtual int IsRenderSupported(
      vtkRenderWindow* vtkNotUsed(window), vtkVolumeProperty* vtkNotUsed(property))
    {
      return 0;
    }
  
    void CreateCanonicalView(vtkRenderer* ren, vtkVolume* volume, vtkImageData* image, int blend_mode,
      double viewDirection[3], double viewUp[3]);
  
    ///@{
    /**
     * Optionally, set a mask input. This mask may be a binary mask or a label
     * map. This must be specified via SetMaskType.
  
     * If the mask is a binary mask, the volume rendering is confined to regions
     * within the binary mask. The binary mask is assumed to have a datatype of
     * UCHAR and values of 255 (inside) and 0 (outside).
  
     * The mask may also be a label map. The label map must have a datatype of
     * UCHAR i.e. it can have upto 256 labels. The label 0 is reserved as a
     * special label. In voxels with label value of 0, the default transfer
     * functions supplied by vtkVolumeProperty are used.
     *
     * For voxels with a label values greater than 0, the color transfer functions
     * supplied using vtkVolumeProperty's label API are used.
     *
     * For voxels with a label value greater than 0, the color transfer function
     * is blended with the default color transfer function, with the blending
     * weight determined by MaskBlendFactor.
     */
    void SetMaskInput(vtkImageData* mask);
    vtkGetObjectMacro(MaskInput, vtkImageData);
    ///@}
  
    enum
    {
      BinaryMaskType = 0,
      LabelMapMaskType
    };
  
    ///@{
    /**
     * Set the mask type, if mask is to be used. See documentation for
     * SetMaskInput(). The default is a LabelMapMaskType.
     */
    vtkSetMacro(MaskType, int);
    vtkGetMacro(MaskType, int);
    void SetMaskTypeToBinary();
    void SetMaskTypeToLabelMap();
    ///@}
  
    ///@{
    /**
     * Tells how much mask color transfer function is used compared to the
     * standard color transfer function when the mask is true. This is relevant
     * only for the label map mask.
     * 0.0 means only standard color transfer function.
     * 1.0 means only mask color transfer function.
     * The default value is 1.0.
     */
    vtkSetClampMacro(MaskBlendFactor, float, 0.0f, 1.0f);
    vtkGetMacro(MaskBlendFactor, float);
    ///@}
  
    ///@{
    /**
     * Enable or disable setting output of volume rendering to be
     * color and depth textures. By default this is set to 0 (off).
     * It should be noted that it is possible that underlying API specific
     * mapper may not supoport RenderToImage mode.
     * \warning
     * \li This method ignores any other volumes / props in the scene.
     * \li This method does not respect the general attributes of the
     * scene i.e. background color, etc. It always produces a color
     * image that has a transparent white background outside the
     * bounds of the volume.
  
     * \sa GetDepthImage(), GetColorImage()
     */
    vtkSetMacro(RenderToImage, vtkTypeBool);
    vtkGetMacro(RenderToImage, vtkTypeBool);
    vtkBooleanMacro(RenderToImage, vtkTypeBool);
    ///@}
  
    ///@{
    /**
     * Set/Get the scalar type of the depth texture in RenderToImage mode.
     * By default, the type if VTK_FLOAT.
     * \sa SetRenderToImage()
     */
    vtkSetMacro(DepthImageScalarType, int);
    vtkGetMacro(DepthImageScalarType, int);
    void SetDepthImageScalarTypeToUnsignedChar();
    void SetDepthImageScalarTypeToUnsignedShort();
    void SetDepthImageScalarTypeToFloat();
    ///@}
  
    ///@{
    /**
     * Enable or disable clamping the depth value of the fully
     * transparent voxel to the depth of the back-face of the
     * volume. This parameter is used when RenderToImage mode is
     * enabled. When ClampDepthToBackFace is false, the fully transparent
     * voxels will have a value of 1.0 in the depth image. When
     * this is true, the fully transparent voxels will have the
     * depth value of the face at which the ray exits the volume.
     * By default, this is set to 0 (off).
     * \sa SetRenderToImage(), GetDepthImage()
     */
    vtkSetMacro(ClampDepthToBackface, vtkTypeBool);
    vtkGetMacro(ClampDepthToBackface, vtkTypeBool);
    vtkBooleanMacro(ClampDepthToBackface, vtkTypeBool);
    ///@}
  
    /**
     * Low level API to export the depth texture as vtkImageData in
     * RenderToImage mode.
     * Should be implemented by the graphics API specific mapper (GL or other).
     * \sa SetRenderToImage()
     */
    virtual void GetDepthImage(vtkImageData*) {}
  
    /**
     * Low level API to export the color texture as vtkImageData in
     * RenderToImage mode.
     * Should be implemented by the graphics API specific mapper (GL or other).
     * \sa SetRenderToImage()
     */
    virtual void GetColorImage(vtkImageData*) {}
  
    /**
     * Initialize rendering for this volume.
     * \warning INTERNAL METHOD - NOT INTENDED FOR GENERAL USE
     */
    void Render(vtkRenderer*, vtkVolume*) override;
  
    /**
     * Handled in the subclass - the actual render method
     * \pre input is up-to-date.
     */
    virtual void GPURender(vtkRenderer*, vtkVolume*) {}
  
    /**
     * Release any graphics resources that are being consumed by this mapper.
     * The parameter window could be used to determine which graphic
     * resources to release.
     * \warning INTERNAL METHOD - NOT INTENDED FOR GENERAL USE
     */
    void ReleaseGraphicsResources(vtkWindow*) override {}
  
    /**
     * Return how much the dataset has to be reduced in each dimension to
     * fit on the GPU. If the value is 1.0, there is no need to reduce the
     * dataset.
     * \pre the calling thread has a current OpenGL context.
     * \pre mapper_supported: IsRenderSupported(renderer->GetRenderWindow(),0)
     * The computation is based on hardware limits (3D texture indexable size)
     * and MaxMemoryInBytes.
     * \post valid_i_ratio: ratio[0]>0 && ratio[0]<=1.0
     * \post valid_j_ratio: ratio[1]>0 && ratio[1]<=1.0
     * \post valid_k_ratio: ratio[2]>0 && ratio[2]<=1.0
     */
    virtual void GetReductionRatio(double ratio[3]) = 0;
  
    enum TFRangeType
    {
      SCALAR = 0, // default
      NATIVE
    };
  
    ///@{
    /**
     * Set whether to use the scalar range or the native transfer function range
     * when looking up transfer functions for color and opacity values. When the
     * range is set to TransferFunctionRange::SCALAR, the function is distributed
     * over the entire scalar range. If it is set to
     * TransferFunctionRange::NATIVE, the scalar values outside the native
     * transfer function range will be truncated to native range. By
     * default, the volume scalar range is used.
     *
     * \note The native range of the transfer function is the range returned by
     * vtkColorTransferFunction::GetRange() or vtkPiecewiseFunction::GetRange().
     *
     * \note There is no special API provided for 2D transfer functions
     * considering that they are set as a pre-generated vtkImageData on this
     * class i.e. the range is already encoded.
     */
    vtkSetMacro(ColorRangeType, int);
    vtkGetMacro(ColorRangeType, int);
    vtkSetMacro(ScalarOpacityRangeType, int);
    vtkGetMacro(ScalarOpacityRangeType, int);
    vtkSetMacro(GradientOpacityRangeType, int);
    vtkGetMacro(GradientOpacityRangeType, int);
    ///@}
  
    vtkDataSet* GetInput() override { return this->GetInput(0); };
  
    ///@{
    /**
     * Add/Remove input connections. Active and removed ports are cached in
     * Ports and RemovedPorts respectively.
     */
    void RemoveInputConnection(int port, vtkAlgorithmOutput* input) override;
    void RemoveInputConnection(int port, int idx) override;
    void SetInputConnection(int port, vtkAlgorithmOutput* input) override;
    void SetInputConnection(vtkAlgorithmOutput* input) override
    {
      this->SetInputConnection(0, input);
    }
    ///@}
  
    /**
     * Number of currently active ports.
     */
    int GetInputCount();
  
    vtkDataSet* GetTransformedInput(const int port = 0);
  
    double* GetBoundsFromPort(const int port) VTK_SIZEHINT(6);
  
  protected:
    vtkGPUVolumeRayCastMapper();
    ~vtkGPUVolumeRayCastMapper() override;
  
    /**
     * Handle inputs. This mapper provides an interface to support multiple
     * inputs but it is up to the OpenGL implementation use them during rendering.
     * Currently, only VolumeOpenGL2/vtkOpenGLGPUVolumeRayCastMapper makes use
     * of these inputs.
     *
     * \sa vtkOpenGLGPUVolumeRayCastMapper vtkMultiVolume
     */
    int FillInputPortInformation(int port, vtkInformation* info) override;
  
    /**
     * A transformation is applied (translation) to the input.  The resulting
     * data is stored in TransformedInputs. Takes as an argumet the port of an
     * input connection.
     *
     * ///TODO Elaborate on why this is an issue, texture coords (?)
     * \todo This is the workaround to deal with GPUVolumeRayCastMapper
     * not able to handle extents starting from non zero values.
     * There is not a easy fix in the GPU volume ray cast mapper hence
     * this fix has been introduced.
     */
    void TransformInput(const int port);
  
    ///@{
    /**
     * This method is used by the Render() method to validate everything before
     * attempting to render. This method returns 0 if something is not right -
     * such as missing input, a null renderer or a null volume, no scalars, etc.
     * In some cases it will produce a vtkErrorMacro message, and in others
     * (for example, in the case of cropping planes that define a region with
     * a volume or 0 or less) it will fail silently. If everything is OK, it will
     * return with a value of 1.
     */
    int ValidateRender(vtkRenderer*, vtkVolume*);
    int ValidateInputs();
    int ValidateInput(vtkVolumeProperty* property, const int port);
    ///@}
  
    ///@{
    /**
     * Shallow-copy the inputs into a transform-adjusted clone.
     * \sa vtkGPUVolumeRayCastMapper::TransformInput
     */
    void CloneInputs();
    void CloneInput(vtkDataSet* input, const int port);
    ///@}
  
    // Special version of render called during the creation
    // of a canonical view.
    void CanonicalViewRender(vtkRenderer*, vtkVolume*);
  
    // Methods called by the AMR Volume Mapper.
    virtual void PreRender(vtkRenderer* ren, vtkVolume* vol, double datasetBounds[6],
      double scalarRange[2], int numberOfScalarComponents, unsigned int numberOfLevels) = 0;
  
    // \pre input is up-to-date
    virtual void RenderBlock(vtkRenderer* ren, vtkVolume* vol, unsigned int level) = 0;
  
    virtual void PostRender(vtkRenderer* ren, int numberOfScalarComponents) = 0;
    vtkDataSet* GetInput(const int port) override;
  
    /**
     * Called by the AMR Volume Mapper.
     * Set the flag that tells if the scalars are on point data (0) or
     * cell data (1).
     */
    void SetCellFlag(int cellFlag);
    void RemovePortInternal(const int port);
  
    vtkTypeBool LockSampleDistanceToInputSpacing;
    vtkTypeBool AutoAdjustSampleDistances;
    float ImageSampleDistance;
    float MinimumImageSampleDistance;
    float MaximumImageSampleDistance;
  
    // Render to texture mode flag
    vtkTypeBool RenderToImage;
  
    // Depth image scalar type
    int DepthImageScalarType;
  
    // Clamp depth values to the depth of the face at which the ray
    // exits the volume
    vtkTypeBool ClampDepthToBackface;
  
    // Enable / disable stochastic jittering
    vtkTypeBool UseJittering;
  
    // Enable / disable two pass rendering
    vtkTypeBool UseDepthPass;
    vtkContourValues* DepthPassContourValues;
  
    // The distance between sample points along the ray
    float SampleDistance;
  
    int SmallVolumeRender;
    double BigTimeToDraw;
    double SmallTimeToDraw;
  
    float FinalColorWindow;
    float FinalColorLevel;
  
    // 1 if we are generating the canonical image, 0 otherwise
    int GeneratingCanonicalView;
    vtkImageData* CanonicalViewImageData;
  
    ///@{
    /**
     * Set the mapper in AMR Mode or not. Initial value is false.
     * Called only by the vtkKWAMRVolumeMapper
     */
    vtkSetClampMacro(AMRMode, vtkTypeBool, 0, 1);
    vtkGetMacro(AMRMode, vtkTypeBool);
    vtkBooleanMacro(AMRMode, vtkTypeBool);
    ///@}
  
    vtkImageData* MaskInput;
    float MaskBlendFactor;
    int MaskType;
  
    vtkTypeBool AMRMode;
  
    // Transfer function range type
    int ColorRangeType;
    int ScalarOpacityRangeType;
    int GradientOpacityRangeType;
  
    // Point data or cell data (or field data, not handled) ?
    int CellFlag;
  
    /**
     * Compute the cropping planes clipped by the bounds of the volume.
     * The result is put into this->ClippedCroppingRegionPlanes.
     * NOTE: IT WILL BE MOVED UP TO vtkVolumeMapper after bullet proof usage
     * in this mapper. Other subclasses will use the ClippedCroppingRegionsPlanes
     * members instead of CroppingRegionPlanes.
     * \pre volume_exists: this->GetInput()!=0
     * \pre valid_cropping: this->Cropping &&
     * this->CroppingRegionPlanes[0]<this->CroppingRegionPlanes[1] &&
     * this->CroppingRegionPlanes[2]<this->CroppingRegionPlanes[3] &&
     * this->CroppingRegionPlanes[4]<this->CroppingRegionPlanes[5])
     */
    virtual void ClipCroppingRegionPlanes();
  
    using DataMap = std::unordered_map<int, vtkDataSet*>;
    void SetTransformedInput(vtkDataSet*);
    vtkDataSet* FindData(int port, DataMap& container);
  
    double ClippedCroppingRegionPlanes[6];
  
    vtkIdType MaxMemoryInBytes;
    float MaxMemoryFraction;
  
    bool ReportProgress;
    std::vector<int> Ports;
    std::vector<int> RemovedPorts;
    DataMap TransformedInputs;
  
    /**
     * This is needed only to check if the input data has been changed since the last
     * Render() call.
     */
    DataMap LastInputs;
  
  private:
    vtkGPUVolumeRayCastMapper(const vtkGPUVolumeRayCastMapper&) = delete;
    void operator=(const vtkGPUVolumeRayCastMapper&) = delete;
  };
  
  #endif
  