Ignore:
Timestamp:
Jul 10, 2011 5:24:36 PM (13 years ago)
Author:
gah
Message:

update from trunk

Location:
branches/blt4/packages/vizservers/vtkvis
Files:
8 added
19 edited

Legend:

Unmodified
Added
Removed
  • branches/blt4/packages/vizservers/vtkvis/ColorMap.cpp

    r2201 r2302  
    1010#include <cassert>
    1111#include <vtkLookupTable.h>
     12#include <vtkColorTransferFunction.h>
     13#include <vtkPiecewiseFunction.h>
    1214
    1315#include "ColorMap.h"
     
    1517
    1618using namespace Rappture::VtkVis;
     19
     20ColorMap *ColorMap::_default = NULL;
     21ColorMap *ColorMap::_volumeDefault = NULL;
    1722
    1823ColorMap::ColorMap(const std::string& name) :
     
    2126    _numTableEntries(256)
    2227{
     28    _colorTF = vtkSmartPointer<vtkColorTransferFunction>::New();
     29    _colorTF->ClampingOn();
     30    _opacityTF = vtkSmartPointer<vtkPiecewiseFunction>::New();
     31    _opacityTF->ClampingOn();
    2332}
    2433
     
    4352    assert(_lookupTable != NULL);
    4453    return _lookupTable;
     54}
     55
     56/**
     57 * \brief Return a newly allocated color transfer function with values
     58 * scaled to the given data range
     59 */
     60vtkSmartPointer<vtkColorTransferFunction>
     61ColorMap::getColorTransferFunction(double range[2])
     62{
     63    vtkSmartPointer<vtkColorTransferFunction> tf = vtkSmartPointer<vtkColorTransferFunction>::New();
     64    tf->DeepCopy(_colorTF);
     65    double tmp[6];
     66    for (int i = 0; i < tf->GetSize(); i++) {
     67        tf->GetNodeValue(i, tmp);
     68        tmp[0] = range[0] + tmp[0] * (range[1] - range[0]);
     69        tf->SetNodeValue(i, tmp);
     70    }
     71    return tf;
     72}
     73
     74/**
     75 * \brief Return a newly allocated opacity transfer function with values
     76 * scaled to the given data range
     77 */
     78vtkSmartPointer<vtkPiecewiseFunction>
     79ColorMap::getOpacityTransferFunction(double range[2])
     80{
     81    vtkSmartPointer<vtkPiecewiseFunction> tf = vtkSmartPointer<vtkPiecewiseFunction>::New();
     82    tf->DeepCopy(_opacityTF);
     83    double tmp[4];
     84    for (int i = 0; i < tf->GetSize(); i++) {
     85        tf->GetNodeValue(i, tmp);
     86        tmp[0] = range[0] + tmp[0] * (range[1] - range[0]);
     87        tf->SetNodeValue(i, tmp);
     88    }
     89    return tf;
    4590}
    4691
     
    72117    // If we reach here, our control point goes at the end
    73118    _controlPoints.insert(_controlPoints.end(), cp);
     119    _colorTF->AddRGBPoint(cp.value, cp.color[0], cp.color[1], cp.color[2]);
    74120}
    75121
     
    101147    // If we reach here, our control point goes at the end
    102148    _opacityControlPoints.insert(_opacityControlPoints.end(), cp);
     149    _opacityTF->AddPoint(cp.value, cp.alpha);
    103150}
    104151
     
    195242}
    196243
     244/**
     245 * \brief Perform linear interpolation of two color control points
     246 */
    197247void ColorMap::lerp(double *result, const ControlPoint& cp1, const ControlPoint& cp2, double value)
    198248{
     
    203253}
    204254
     255/**
     256 * \brief Perform linear interpolation of two opacity control points
     257 */
    205258void ColorMap::lerp(double *result, const OpacityControlPoint& cp1, const OpacityControlPoint& cp2, double value)
    206259{
     
    215268{
    216269    _controlPoints.clear();
     270    _colorTF->RemoveAllPoints();
    217271    _opacityControlPoints.clear();
     272    _opacityTF->RemoveAllPoints();
    218273    _lookupTable = NULL;
    219274}
     
    222277 * \brief Create a default ColorMap with a blue-cyan-green-yellow-red ramp
    223278 */
    224 ColorMap * ColorMap::createDefault()
    225 {
    226     ColorMap *colorMap = new ColorMap("default");
     279ColorMap * ColorMap::getDefault()
     280{
     281    if (_default != NULL) {
     282        return _default;
     283    }
     284
     285    _default = new ColorMap("default");
    227286    ControlPoint cp[5];
    228287    cp[0].value = 0.0;
     
    247306    cp[4].color[2] = 0.0;
    248307    for (int i = 0; i < 5; i++) {
    249         colorMap->addControlPoint(cp[i]);
     308        _default->addControlPoint(cp[i]);
    250309    }
    251310    OpacityControlPoint ocp[2];
     
    254313    ocp[1].value = 1.0;
    255314    ocp[1].alpha = 1.0;
    256     colorMap->addOpacityControlPoint(ocp[0]);
    257     colorMap->addOpacityControlPoint(ocp[1]);
    258     colorMap->build();
    259     return colorMap;
    260 }
     315    _default->addOpacityControlPoint(ocp[0]);
     316    _default->addOpacityControlPoint(ocp[1]);
     317    _default->build();
     318    return _default;
     319}
     320
     321/**
     322 * \brief Create a default ColorMap with a blue-cyan-green-yellow-red ramp
     323 * and transparent to opaque ramp
     324 */
     325ColorMap * ColorMap::getVolumeDefault()
     326{
     327    if (_volumeDefault != NULL) {
     328        return _volumeDefault;
     329    }
     330
     331    _volumeDefault = new ColorMap("volumeDefault");
     332    ControlPoint cp[5];
     333    cp[0].value = 0.0;
     334    cp[0].color[0] = 0.0;
     335    cp[0].color[1] = 0.0;
     336    cp[0].color[2] = 1.0;
     337    cp[1].value = 0.25;
     338    cp[1].color[0] = 0.0;
     339    cp[1].color[1] = 1.0;
     340    cp[1].color[2] = 1.0;
     341    cp[2].value = 0.5;
     342    cp[2].color[0] = 0.0;
     343    cp[2].color[1] = 1.0;
     344    cp[2].color[2] = 0.0;
     345    cp[3].value = 0.75;
     346    cp[3].color[0] = 1.0;
     347    cp[3].color[1] = 1.0;
     348    cp[3].color[2] = 0.0;
     349    cp[4].value = 1.0;
     350    cp[4].color[0] = 1.0;
     351    cp[4].color[1] = 0.0;
     352    cp[4].color[2] = 0.0;
     353    for (int i = 0; i < 5; i++) {
     354        _volumeDefault->addControlPoint(cp[i]);
     355    }
     356    OpacityControlPoint ocp[2];
     357    ocp[0].value = 0.0;
     358    ocp[0].alpha = 0.0;
     359    ocp[1].value = 1.0;
     360    ocp[1].alpha = 1.0;
     361    _volumeDefault->addOpacityControlPoint(ocp[0]);
     362    _volumeDefault->addOpacityControlPoint(ocp[1]);
     363    _volumeDefault->build();
     364    return _volumeDefault;
     365}
  • branches/blt4/packages/vizservers/vtkvis/ColorMap.h

    r2201 r2302  
    1313#include <cstring>
    1414#include <vtkSmartPointer.h>
     15#include <vtkColorTransferFunction.h>
     16#include <vtkPiecewiseFunction.h>
    1517#include <vtkLookupTable.h>
    1618
     
    8486
    8587    const std::string& getName();
     88
    8689    vtkLookupTable *getLookupTable();
     90
     91    vtkSmartPointer<vtkColorTransferFunction> getColorTransferFunction(double range[2]);
     92
     93    vtkSmartPointer<vtkPiecewiseFunction> getOpacityTransferFunction(double range[2]);
    8794
    8895    void setNumberOfTableEntries(int numEntries);
     
    96103    void clear();
    97104
    98     static ColorMap* createDefault();
     105    static ColorMap *getDefault();
     106    static ColorMap *getVolumeDefault();
    99107
    100108private:
     109    static ColorMap *_default;
     110    static ColorMap *_volumeDefault;
     111
    101112    ColorMap();
    102113
     
    109120    bool _needsBuild;
    110121    int _numTableEntries;
     122    vtkSmartPointer<vtkColorTransferFunction> _colorTF;
     123    vtkSmartPointer<vtkPiecewiseFunction> _opacityTF;
    111124    vtkSmartPointer<vtkLookupTable> _lookupTable;
    112125};
  • branches/blt4/packages/vizservers/vtkvis/Makefile.in

    r2120 r2302  
    2323MKDIR_P         = @MKDIR_P@
    2424
     25GL_LIB_SPEC     = -lGL
     26
    2527TCL_LIB_SPEC    = @TCL_LIB_SPEC@
    2628TCL_INC_SPEC    = @TCL_INC_SPEC@
    2729
    2830VTK_LIB_DIR     = @VTK_LIB_DIR@
    29 VTK_LIB_SPEC    = -L$(VTK_LIB_DIR) -lvtkIO -lvtkWidgets -lvtkRendering -lvtkGraphics -lvtkCommon
     31VTK_LIB_SPEC    = -L$(VTK_LIB_DIR) -lvtkIO -lvtkWidgets -lvtkFiltering -lvtkVolumeRendering -lvtkRendering -lvtkHybrid -lvtkGraphics -lvtkImaging -lvtkCommon
    3032VTK_INC_SPEC    = @VTK_INC_SPEC@
    3133
     
    3335
    3436LIBS            = \
     37                $(GL_LIB_SPEC) \
    3538                $(TCL_LIB_SPEC) \
    3639                $(VTK_LIB_SPEC) \
    37                 -Wl,-rpath-link,$(LD_RUN_PATH)
     40                -Wl,-rpath,$(LD_RUN_PATH)
    3841
    3942INCLUDES        = \
     
    4245                $(VTK_INC_SPEC)
    4346
    44 USE_CUSTOM_AXES = #yes
    45 DEBUG           = #yes
    46 TRACE           = #yes
     47DEBUG                   = #yes
     48TRACE                   = #yes
     49USE_CUSTOM_AXES         = #yes
     50USE_GPU_RAYCASTING      = yes
     51USE_OFFSCREEN_RENDERING = yes
    4752
    4853EXTRA_CFLAGS    = -Wall -Wno-deprecated #vtk uses deprecated strstream header (instead of sstream)
     
    5863DEFINES         += -DUSE_CUSTOM_AXES
    5964endif
     65ifdef USE_OFFSCREEN_RENDERING
     66DEFINES         += -DUSE_OFFSCREEN_RENDERING
     67endif
     68ifdef USE_GPU_RAYCASTING
     69DEFINES         += -DUSE_GPU_RAYCAST_MAPPER
     70endif
    6071CXX_SWITCHES    = $(CXXFLAGS) $(EXTRA_CFLAGS) $(DEFINES) $(INCLUDES)
    6172
     
    6576                PPMWriter.cpp \
    6677                RpContour2D.cpp \
     78                RpContour3D.cpp \
     79                RpGlyphs.cpp \
     80                RpHeightMap.cpp \
    6781                RpPolyData.cpp \
    6882                RpPseudoColor.cpp \
     83                RpVolume.cpp \
    6984                RpVtkDataSet.cpp \
    7085                RpVtkRenderer.cpp\
     
    112127PPMWriter.o: PPMWriter.h Trace.h
    113128RpContour2D.o: RpContour2D.h RpVtkDataSet.h Trace.h
     129RpContour3D.o: RpContour3D.h RpVtkDataSet.h Trace.h
    114130RpPolyData.o: RpPolyData.h RpVtkDataSet.h Trace.h
     131RpGlyphs.o: RpGlyphs.h RpVtkDataSet.h ColorMap.h Trace.h
     132RpHeightMap.o: RpHeightMap.h RpVtkDataSet.h Trace.h
    115133RpPseudoColor.o: RpPseudoColor.h RpVtkDataSet.h Trace.h
     134RpVolume.o: RpVolume.h RpVtkDataSet.h ColorMap.h Trace.h
    116135RpVtkDataSet.o: RpVtkDataSet.h Trace.h
    117136RpVtkRenderer.o: RpVtkRenderer.h RpVtkDataSet.h RpPolyData.h RpPseudoColor.h RpContour2D.h ColorMap.h Trace.h
    118 RpVtkRendererCmd.o: RpVtkRenderer.h RpVtkDataSet.h RpPseudoColor.h RpContour2D.h Trace.h CmdProc.h PPMWriter.h TGAWriter.h ColorMap.h
    119 RpVtkRenderServer.o: RpVtkRenderServer.h RpVtkRenderer.h RpVtkDataSet.h RpPseudoColor.h RpContour2D.h Trace.h
     137RpVtkRendererCmd.o: RpVtkRenderer.h RpVtkDataSet.h RpPseudoColor.h RpContour2D.h Trace.h CmdProc.h ColorMap.h PPMWriter.h TGAWriter.h
     138RpVtkRenderServer.o: RpVtkRenderServer.h RpVtkRenderer.h RpVtkDataSet.h RpPseudoColor.h RpContour2D.h Trace.h PPMWriter.h TGAWriter.h
    120139Trace.o: Trace.h
    121140TGAWriter.o: TGAWriter.h Trace.h
  • branches/blt4/packages/vizservers/vtkvis/PPMWriter.cpp

    r2120 r2302  
    3131 * routine could be made even simpler (faster) if the image data had top
    3232 * to bottom scanlines.
     33 *
     34 * \param[in] fd File descriptor that will be written to
     35 * \param[in] cmdName Command name to send (byte length will be appended)
     36 * \param[in] data Image data
     37 * \param[in] width Width of image in pixels
     38 * \param[in] height Height of image in pixels
    3339 */
    3440void
  • branches/blt4/packages/vizservers/vtkvis/RpContour2D.cpp

    r2201 r2302  
    66 */
    77
     8#include <cassert>
     9
     10#include <vtkDataSet.h>
     11#include <vtkPointData.h>
     12#include <vtkCellData.h>
     13#include <vtkCellDataToPointData.h>
    814#include <vtkContourFilter.h>
    915#include <vtkPolyDataMapper.h>
     16#include <vtkUnstructuredGrid.h>
    1017#include <vtkProperty.h>
     18#include <vtkDelaunay2D.h>
     19#include <vtkDelaunay3D.h>
     20#include <vtkDataSetSurfaceFilter.h>
    1121
    1222#include "RpContour2D.h"
     
    6676
    6777/**
    68  * \brief Get the VTK Actor for the contour lines
    69  */
    70 vtkActor *Contour2D::getActor()
     78 * \brief Get the VTK Prop for the contour lines
     79 */
     80vtkProp *Contour2D::getProp()
    7181{
    7282    return _contourActor;
     
    7484
    7585/**
    76  * \brief Create and initialize a VTK actor to render isolines
    77  */
    78 void Contour2D::initActor()
     86 * \brief Create and initialize a VTK Prop to render isolines
     87 */
     88void Contour2D::initProp()
    7989{
    8090    if (_contourActor == NULL) {
     
    96106        return;
    97107    }
    98 
    99     initActor();
     108    vtkDataSet *ds = _dataSet->getVtkDataSet();
     109
     110    initProp();
    100111
    101112    // Contour filter to generate isolines
     
    104115    }
    105116
    106     _contourFilter->SetInput(_dataSet->getVtkDataSet());
     117    vtkSmartPointer<vtkCellDataToPointData> cellToPtData;
     118
     119    if (ds->GetPointData() == NULL ||
     120        ds->GetPointData()->GetScalars() == NULL) {
     121        WARN("No scalar point data in dataset %s", _dataSet->getName().c_str());
     122        if (ds->GetCellData() != NULL &&
     123            ds->GetCellData()->GetScalars() != NULL) {
     124            cellToPtData =
     125                vtkSmartPointer<vtkCellDataToPointData>::New();
     126            cellToPtData->SetInput(ds);
     127            //cellToPtData->PassCellDataOn();
     128            cellToPtData->Update();
     129            ds = cellToPtData->GetOutput();
     130        } else {
     131            ERROR("No scalar cell data in dataset %s", _dataSet->getName().c_str());
     132        }
     133    }
     134
     135    vtkPolyData *pd = vtkPolyData::SafeDownCast(ds);
     136    if (pd) {
     137        // DataSet is a vtkPolyData
     138        if (pd->GetNumberOfLines() == 0 &&
     139            pd->GetNumberOfPolys() == 0 &&
     140            pd->GetNumberOfStrips() == 0) {
     141            // DataSet is a point cloud
     142            if (_dataSet->is2D()) {
     143                vtkSmartPointer<vtkDelaunay2D> mesher = vtkSmartPointer<vtkDelaunay2D>::New();
     144                mesher->SetInput(pd);
     145                _contourFilter->SetInputConnection(mesher->GetOutputPort());
     146            } else {
     147                vtkSmartPointer<vtkDelaunay3D> mesher = vtkSmartPointer<vtkDelaunay3D>::New();
     148                mesher->SetInput(pd);
     149                vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
     150                gf->SetInputConnection(mesher->GetOutputPort());
     151                _contourFilter->SetInputConnection(gf->GetOutputPort());
     152            }
     153        } else {
     154            // DataSet is a vtkPolyData with lines and/or polygons
     155            _contourFilter->SetInput(ds);
     156        }
     157    } else {
     158        TRACE("Generating surface for data set");
     159        // DataSet is NOT a vtkPolyData
     160        vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
     161        gf->SetInput(ds);
     162        _contourFilter->SetInputConnection(gf->GetOutputPort());
     163    }
    107164
    108165    _contourFilter->ComputeNormalsOff();
     
    130187        _contourMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    131188        _contourMapper->SetResolveCoincidentTopologyToPolygonOffset();
     189        _contourMapper->SetInputConnection(_contourFilter->GetOutputPort());
    132190        _contourActor->SetMapper(_contourMapper);
    133         _contourMapper->SetInput(_contourFilter->GetOutput());
    134     }
     191    }
     192
     193    _contourMapper->Update();
    135194}
    136195
  • branches/blt4/packages/vizservers/vtkvis/RpContour2D.h

    r2201 r2302  
    3434    DataSet *getDataSet();
    3535
    36     vtkActor *getActor();
     36    vtkProp *getProp();
    3737
    3838    void setContours(int numContours);
     
    6161
    6262private:
    63     void initActor();
     63    void initProp();
    6464    void update();
    6565
  • branches/blt4/packages/vizservers/vtkvis/RpPolyData.cpp

    r2170 r2302  
    66 */
    77
     8#include <cassert>
     9
    810#include <vtkDataSet.h>
    911#include <vtkPolyData.h>
     12#include <vtkUnstructuredGrid.h>
    1013#include <vtkPolyDataMapper.h>
    1114#include <vtkActor.h>
    1215#include <vtkProperty.h>
     16#include <vtkDelaunay2D.h>
     17#include <vtkDelaunay3D.h>
     18#include <vtkDataSetSurfaceFilter.h>
    1319
    1420#include "RpPolyData.h"
     
    1824
    1925PolyData::PolyData() :
     26    _dataSet(NULL),
    2027    _edgeWidth(1.0),
    2128    _opacity(1.0),
     
    4148
    4249/**
    43  * \brief Get the VTK Actor for the mesh
    44  */
    45 vtkActor *PolyData::getActor()
     50 * \brief Get the VTK Prop for the mesh
     51 */
     52vtkProp *PolyData::getProp()
    4653{
    4754    return _pdActor;
     
    4956
    5057/**
    51  * \brief Create and initialize a VTK actor to render a mesh
    52  */
    53 void PolyData::initActor()
     58 * \brief Create and initialize a VTK Prop to render a mesh
     59 */
     60void PolyData::initProp()
    5461{
    5562    if (_pdActor == NULL) {
     
    7380{
    7481    if (_dataSet != dataSet) {
    75         vtkDataSet *ds = dataSet->getVtkDataSet();
    76         if (!ds->IsA("vtkPolyData")) {
    77             ERROR("DataSet is not a PolyData");
    78             return;
    79         }
    80         TRACE("DataSet is a vtkPolyData");
    8182        _dataSet = dataSet;
    8283        update();
     
    107108    }
    108109
    109     initActor();
     110    vtkDataSet *ds = _dataSet->getVtkDataSet();
     111    vtkPolyData *pd = vtkPolyData::SafeDownCast(ds);
     112    if (pd) {
     113        TRACE("Verts: %d Lines: %d Polys: %d Strips: %d",
     114                  pd->GetNumberOfVerts(),
     115                  pd->GetNumberOfLines(),
     116                  pd->GetNumberOfPolys(),
     117                  pd->GetNumberOfStrips());
     118        // DataSet is a vtkPolyData
     119        if (pd->GetNumberOfLines() == 0 &&
     120            pd->GetNumberOfPolys() == 0 &&
     121            pd->GetNumberOfStrips() == 0) {
     122            // DataSet is a point cloud
     123            if (_dataSet->is2D()) {
     124                vtkSmartPointer<vtkDelaunay2D> mesher = vtkSmartPointer<vtkDelaunay2D>::New();
     125                mesher->SetInput(pd);
     126#if defined(DEBUG) && defined(WANT_TRACE)
     127                mesher->Update();
     128                vtkPolyData *outpd = mesher->GetOutput();
     129                TRACE("Delaunay2D Verts: %d Lines: %d Polys: %d Strips: %d",
     130                      outpd->GetNumberOfVerts(),
     131                      outpd->GetNumberOfLines(),
     132                      outpd->GetNumberOfPolys(),
     133                      outpd->GetNumberOfStrips());
     134#endif
     135                _pdMapper->SetInputConnection(mesher->GetOutputPort());
     136            } else {
     137                vtkSmartPointer<vtkDelaunay3D> mesher = vtkSmartPointer<vtkDelaunay3D>::New();
     138                mesher->SetInput(pd);
     139                // Delaunay3D returns an UnstructuredGrid, so feed it through a surface filter
     140                // to get the grid boundary as a PolyData
     141                vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
     142                gf->SetInputConnection(mesher->GetOutputPort());
     143                _pdMapper->SetInputConnection(gf->GetOutputPort());
     144            }
     145        } else {
     146            // DataSet is a vtkPolyData with lines and/or polygons
     147            _pdMapper->SetInput(pd);
     148        }
     149    } else {
     150        // DataSet is NOT a vtkPolyData
     151        WARN("DataSet is not a PolyData");
     152        vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
     153        gf->SetInput(ds);
     154        _pdMapper->SetInputConnection(gf->GetOutputPort());
     155    }
     156
     157    initProp();
    110158    _pdActor->SetMapper(_pdMapper);
    111 
    112     _pdMapper->SetInput(vtkPolyData::SafeDownCast(_dataSet->getVtkDataSet()));
     159    _pdMapper->Update();
    113160}
    114161
  • branches/blt4/packages/vizservers/vtkvis/RpPolyData.h

    r2170 r2302  
    3232    DataSet *getDataSet();
    3333
    34     vtkActor *getActor();
     34    vtkProp *getProp();
    3535
    3636    void setVisibility(bool state);
     
    5555
    5656private:
    57     void initActor();
     57    void initProp();
    5858    void update();
    5959
  • branches/blt4/packages/vizservers/vtkvis/RpPseudoColor.cpp

    r2201 r2302  
    66 */
    77
     8#include <cassert>
     9
    810#include <vtkDataSet.h>
     11#include <vtkPointData.h>
    912#include <vtkDataSetMapper.h>
     13#include <vtkUnstructuredGrid.h>
    1014#include <vtkProperty.h>
    11 #include <vtkPointData.h>
     15#include <vtkImageData.h>
    1216#include <vtkLookupTable.h>
     17#include <vtkDelaunay2D.h>
     18#include <vtkDelaunay3D.h>
     19#include <vtkGaussianSplatter.h>
     20#include <vtkExtractVOI.h>
     21#include <vtkDataSetSurfaceFilter.h>
    1322
    1423#include "RpPseudoColor.h"
    1524#include "Trace.h"
     25
     26#define MESH_POINT_CLOUDS
    1627
    1728using namespace Rappture::VtkVis;
     
    4455void PseudoColor::setDataSet(DataSet *dataSet)
    4556{
    46     _dataSet = dataSet;
    47     update();
     57    if (_dataSet != dataSet) {
     58        _dataSet = dataSet;
     59        update();
     60    }
    4861}
    4962
     
    7386        _dsMapper = vtkSmartPointer<vtkDataSetMapper>::New();
    7487    }
    75     _dsMapper->SetInput(ds);
    76     _dsMapper->StaticOff();
     88
     89    vtkPolyData *pd = vtkPolyData::SafeDownCast(ds);
     90    if (pd) {
     91        // DataSet is a vtkPolyData
     92        if (pd->GetNumberOfLines() == 0 &&
     93            pd->GetNumberOfPolys() == 0 &&
     94            pd->GetNumberOfStrips() == 0) {
     95            // DataSet is a point cloud
     96            if (_dataSet->is2D()) {
     97#ifdef MESH_POINT_CLOUDS
     98                vtkSmartPointer<vtkDelaunay2D> mesher = vtkSmartPointer<vtkDelaunay2D>::New();
     99                mesher->SetInput(pd);
     100                vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
     101                gf->SetInputConnection(mesher->GetOutputPort());
     102                _dsMapper->SetInputConnection(gf->GetOutputPort());
     103#else
     104                vtkSmartPointer<vtkGaussianSplatter> splatter = vtkSmartPointer<vtkGaussianSplatter>::New();
     105                splatter->SetInput(pd);
     106                int dims[3];
     107                splatter->GetSampleDimensions(dims);
     108                TRACE("Sample dims: %d %d %d", dims[0], dims[1], dims[2]);
     109                dims[2] = 3;
     110                splatter->SetSampleDimensions(dims);
     111                double bounds[6];
     112                splatter->Update();
     113                splatter->GetModelBounds(bounds);
     114                TRACE("Model bounds: %g %g %g %g %g %g",
     115                      bounds[0], bounds[1],
     116                      bounds[2], bounds[3],
     117                      bounds[4], bounds[5]);
     118                vtkSmartPointer<vtkExtractVOI> slicer = vtkSmartPointer<vtkExtractVOI>::New();
     119                slicer->SetInputConnection(splatter->GetOutputPort());
     120                slicer->SetVOI(0, dims[0]-1, 0, dims[1]-1, 1, 1);
     121                slicer->SetSampleRate(1, 1, 1);
     122                vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
     123                gf->UseStripsOn();
     124                gf->SetInputConnection(slicer->GetOutputPort());
     125                _dsMapper->SetInputConnection(gf->GetOutputPort());
     126#endif
     127            } else {
     128                vtkSmartPointer<vtkDelaunay3D> mesher = vtkSmartPointer<vtkDelaunay3D>::New();
     129                mesher->SetInput(pd);
     130                vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
     131                gf->SetInputConnection(mesher->GetOutputPort());
     132                _dsMapper->SetInputConnection(gf->GetOutputPort());
     133             }
     134        } else {
     135            // DataSet is a vtkPolyData with lines and/or polygons
     136            _dsMapper->SetInput(ds);
     137        }
     138    } else {
     139        TRACE("Generating surface for data set");
     140        // DataSet is NOT a vtkPolyData
     141        vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
     142        gf->SetInput(ds);
     143        _dsMapper->SetInputConnection(gf->GetOutputPort());
     144    }
    77145
    78146    if (ds->GetPointData() == NULL ||
    79147        ds->GetPointData()->GetScalars() == NULL) {
    80         ERROR("No scalar point data in dataset %s", _dataSet->getName().c_str());
     148        WARN("No scalar point data in dataset %s", _dataSet->getName().c_str());
    81149        if (_lut == NULL) {
    82150            _lut = vtkSmartPointer<vtkLookupTable>::New();
     
    95163    _lut->SetRange(dataRange);
    96164
     165    _dsMapper->SetColorModeToMapScalars();
    97166    _dsMapper->UseLookupTableScalarRangeOn();
    98167    _dsMapper->SetLookupTable(_lut);
    99168    //_dsMapper->InterpolateScalarsBeforeMappingOn();
    100169
    101     initActor();
     170    initProp();
    102171    _dsActor->SetMapper(_dsMapper);
    103 }
    104 
    105 /**
    106  * \brief Get the VTK Actor for the colormapped dataset
    107  */
    108 vtkActor *PseudoColor::getActor()
     172    _dsMapper->Update();
     173}
     174
     175/**
     176 * \brief Get the VTK Prop for the colormapped dataset
     177 */
     178vtkProp *PseudoColor::getProp()
    109179{
    110180    return _dsActor;
     
    112182
    113183/**
    114  * \brief Create and initialize a VTK actor to render the colormapped dataset
    115  */
    116 void PseudoColor::initActor()
     184 * \brief Create and initialize a VTK Prop to render the colormapped dataset
     185 */
     186void PseudoColor::initProp()
    117187{
    118188    if (_dsActor == NULL) {
  • branches/blt4/packages/vizservers/vtkvis/RpPseudoColor.h

    r2170 r2302  
    3434    DataSet *getDataSet();
    3535
    36     vtkActor *getActor();
     36    vtkProp *getProp();
    3737
    3838    void setLookupTable(vtkLookupTable *lut);
     
    5757
    5858private:
    59     void initActor();
     59    void initProp();
    6060    void update();
    6161
  • branches/blt4/packages/vizservers/vtkvis/RpVtkDataSet.cpp

    r2201 r2302  
    88#include <vtkCharArray.h>
    99#include <vtkDataSetReader.h>
    10 #include <vtkDataSetMapper.h>
     10#include <vtkPolyData.h>
     11#include <vtkStructuredPoints.h>
     12#include <vtkStructuredGrid.h>
     13#include <vtkRectilinearGrid.h>
     14#include <vtkUnstructuredGrid.h>
    1115#include <vtkProperty.h>
    1216#include <vtkPointData.h>
     
    2226    _visible(true)
    2327{
    24     _name = name;
    2528    _dataRange[0] = 0;
    2629    _dataRange[1] = 1;
     
    6265{
    6366    vtkSmartPointer<vtkDataSetReader> reader = vtkSmartPointer<vtkDataSetReader>::New();
     67
     68#if defined(WANT_TRACE) && defined(DEBUG)
     69    reader->DebugOn();
     70#endif
     71
    6472    reader->SetFileName(filename);
     73    reader->ReadAllScalarsOn();
     74    reader->ReadAllVectorsOn();
    6575    return setData(reader);
    6676}
     
    7181bool DataSet::setData(char *data, int nbytes)
    7282{
     83    TRACE("Entering");
     84
    7385    vtkSmartPointer<vtkDataSetReader> reader = vtkSmartPointer<vtkDataSetReader>::New();
    7486    vtkSmartPointer<vtkCharArray> dataSetString = vtkSmartPointer<vtkCharArray>::New();
     87
     88#if defined(WANT_TRACE) && defined(DEBUG)
     89    reader->DebugOn();
     90    dataSetString->DebugOn();
     91#endif
    7592
    7693    dataSetString->SetArray(data, nbytes, 1);
    7794    reader->SetInputArray(dataSetString);
    7895    reader->ReadFromInputStringOn();
    79     return setData(reader);
     96    reader->ReadAllScalarsOn();
     97    reader->ReadAllVectorsOn();
     98
     99    bool status = setData(reader);
     100
     101    TRACE("Leaving");
     102    return status;
    80103}
    81104
    82105/**
    83106 * \brief Read dataset using supplied reader
     107 *
     108 * Pipeline information is removed from the resulting
     109 * vtkDataSet, so that the reader and its data can be
     110 * released
    84111 */
    85112bool DataSet::setData(vtkDataSetReader *reader)
     
    87114    // Force reading data set
    88115    reader->SetLookupTableName("");
     116    reader->Update();
     117
    89118    _dataSet = reader->GetOutput();
    90     _dataSet->Update();
    91     _dataSet->GetScalarRange(_dataRange);
    92 
    93     TRACE("Scalar Range: %.12e, %.12e", _dataRange[0], _dataRange[1]);
    94     return true;
    95 }
    96 
    97 /**
    98  * \brief Read dataset using supplied reader
    99  */
    100 bool DataSet::setData(vtkDataSet *ds)
    101 {
    102     _dataSet = ds;
    103     _dataSet->Update();
     119    _dataSet->SetPipelineInformation(NULL);
     120
    104121    _dataSet->GetScalarRange(_dataRange);
    105122    _dataSet->GetBounds(_bounds);
    106123
     124    TRACE("DataSet class: %s", _dataSet->GetClassName());
    107125    TRACE("Scalar Range: %.12e, %.12e", _dataRange[0], _dataRange[1]);
     126    TRACE("DataSet bounds: %g %g %g %g %g %g",
     127          _bounds[0], _bounds[1],
     128          _bounds[2], _bounds[3],
     129          _bounds[4], _bounds[5]);
    108130    return true;
    109131}
    110132
    111133/**
     134 * \brief Set DataSet from existing vtkDataSet object
     135 *
     136 * Pipeline information is removed from the supplied vtkDataSet
     137 */
     138bool DataSet::setData(vtkDataSet *ds)
     139{
     140    _dataSet = ds;
     141    _dataSet->SetPipelineInformation(NULL);
     142    _dataSet->GetScalarRange(_dataRange);
     143    _dataSet->GetBounds(_bounds);
     144
     145    TRACE("DataSet class: %s", _dataSet->GetClassName());
     146    TRACE("Scalar Range: %.12e, %.12e", _dataRange[0], _dataRange[1]);
     147    TRACE("DataSet bounds: %g %g %g %g %g %g",
     148          _bounds[0], _bounds[1],
     149          _bounds[2], _bounds[3],
     150          _bounds[4], _bounds[5]);
     151    return true;
     152}
     153
     154/**
     155 * \brief Copy an existing vtkDataSet object
     156 *
     157 * Pipeline information is not copied from the supplied vtkDataSet
     158 * into this DataSet, but pipeline information in the supplied
     159 * vtkDataSet is not removed
     160 */
     161vtkDataSet *DataSet::copyData(vtkDataSet *ds)
     162{
     163    if (vtkPolyData::SafeDownCast(ds) != NULL) {
     164        _dataSet = vtkSmartPointer<vtkPolyData>::New();
     165        _dataSet->DeepCopy(vtkPolyData::SafeDownCast(ds));
     166    } else if (vtkStructuredPoints::SafeDownCast(ds) != NULL) {
     167        _dataSet = vtkSmartPointer<vtkStructuredPoints>::New();
     168        _dataSet->DeepCopy(vtkStructuredPoints::SafeDownCast(ds));
     169    } else if (vtkStructuredGrid::SafeDownCast(ds) != NULL) {
     170        _dataSet = vtkSmartPointer<vtkStructuredGrid>::New();
     171        _dataSet->DeepCopy(vtkStructuredGrid::SafeDownCast(ds));
     172    } else if (vtkRectilinearGrid::SafeDownCast(ds) != NULL) {
     173        _dataSet = vtkSmartPointer<vtkRectilinearGrid>::New();
     174        _dataSet->DeepCopy(vtkRectilinearGrid::SafeDownCast(ds));
     175    } else if (vtkUnstructuredGrid::SafeDownCast(ds) != NULL) {
     176        _dataSet = vtkSmartPointer<vtkUnstructuredGrid>::New();
     177        _dataSet->DeepCopy(vtkUnstructuredGrid::SafeDownCast(ds));
     178    } else {
     179        ERROR("Unknown data type");
     180        return NULL;
     181    }
     182    _dataSet->GetScalarRange(_dataRange);
     183    _dataSet->GetBounds(_bounds);
     184
     185    TRACE("DataSet class: %s", _dataSet->GetClassName());
     186    TRACE("Scalar Range: %.12e, %.12e", _dataRange[0], _dataRange[1]);
     187    return _dataSet;
     188}
     189
     190/**
    112191 * \brief Does DataSet lie in the XY plane (z = 0)
    113192 */
     
    134213
    135214/**
     215 * \brief Get the underlying VTK DataSet subclass class name
     216 */
     217const char *DataSet::getVtkType()
     218{
     219    return _dataSet->GetClassName();
     220}
     221
     222/**
    136223 * \brief Get the range of scalar values in the DataSet
    137224 */
    138225void DataSet::getDataRange(double minmax[2])
    139226{
    140     minmax[0] = _dataRange[0];
    141     minmax[1] = _dataRange[1];
     227    memcpy(minmax, _dataRange, sizeof(double)*2);
     228}
     229
     230/**
     231 * \brief Get the bounds the DataSet
     232 */
     233void DataSet::getBounds(double bounds[6])
     234{
     235    memcpy(bounds, _bounds, sizeof(double)*6);
    142236}
    143237
  • branches/blt4/packages/vizservers/vtkvis/RpVtkDataSet.h

    r2201 r2302  
    2727    virtual ~DataSet();
    2828
     29    bool setDataFile(const char *filename);
     30
    2931    bool setData(char *data, int nbytes);
     32
     33    bool setData(vtkDataSetReader *reader);
    3034
    3135    bool setData(vtkDataSet *ds);
    3236
    33     bool setData(vtkDataSetReader *reader);
    34 
    35     bool setDataFile(const char *filename);
     37    vtkDataSet *copyData(vtkDataSet *ds);
    3638
    3739    bool is2D() const;
     
    4143    vtkDataSet *getVtkDataSet();
    4244
     45    const char *getVtkType();
     46
    4347    void getDataRange(double minmax[2]);
     48
     49    void getBounds(double bounds[6]);
    4450
    4551    double getDataValue(double x, double y, double z);
  • branches/blt4/packages/vizservers/vtkvis/RpVtkRenderServer.cpp

    r2201 r2302  
    1414#include <signal.h>
    1515
     16#ifdef WANT_TRACE
     17#include <sys/time.h>
     18#endif
     19
    1620#include "Trace.h"
    1721#include "RpVtkRenderServer.h"
     
    2933FILE *Rappture::VtkVis::g_fLog = NULL; ///< Trace logging file handle
    3034Renderer *Rappture::VtkVis::g_renderer = NULL; ///< Main render worker
     35
     36#define ELAPSED_TIME(t1, t2) \
     37    ((t1).tv_sec == (t2).tv_sec ? (((t2).tv_usec - (t1).tv_usec)/1.0e+3f) : \
     38     (((t2).tv_sec - (t1).tv_sec))*1.0e+3f + (float)((t2).tv_usec - (t1).tv_usec)/1.0e+3f)
    3139
    3240static void
     
    4452    }
    4553
     54#ifdef RENDER_TARGA
    4655    writeTGAFile("/tmp/frame.tga",
    4756                 imgData->GetPointer(0),
    4857                 g_renderer->getWindowWidth(),
    49                  g_renderer->getWindowHeight());
     58                 g_renderer->getWindowHeight(),
     59                 TARGA_BYTES_PER_PIXEL);
     60#else
     61    writeTGAFile("/tmp/frame.tga",
     62                 imgData->GetPointer(0),
     63                 g_renderer->getWindowWidth(),
     64                 g_renderer->getWindowHeight(),
     65                 TARGA_BYTES_PER_PIXEL,
     66                 true);
     67#endif
     68
    5069#else
    5170    if (g_renderer->getCameraMode() == Renderer::IMAGE) {
     
    6281            << xywh[1] << "} -bytes";
    6382
     83#ifdef RENDER_TARGA
     84        writeTGA(fd, oss.str().c_str(),
     85                 imgData->GetPointer(0),
     86                 g_renderer->getWindowWidth(),
     87                 g_renderer->getWindowHeight(),
     88                 TARGA_BYTES_PER_PIXEL);
     89#else
    6490        writePPM(fd, oss.str().c_str(),
    6591                 imgData->GetPointer(0),
    6692                 g_renderer->getWindowWidth(),
    6793                 g_renderer->getWindowHeight());
     94#endif
    6895    } else {
     96#ifdef RENDER_TARGA
     97        writeTGA(fd, "nv>image -type image -bytes",
     98                 imgData->GetPointer(0),
     99                 g_renderer->getWindowWidth(),
     100                 g_renderer->getWindowHeight(),
     101                 TARGA_BYTES_PER_PIXEL);
     102#else
    69103        writePPM(fd, "nv>image -type image -bytes",
    70104                 imgData->GetPointer(0),
    71105                 g_renderer->getWindowWidth(),
    72106                 g_renderer->getWindowHeight());
     107#endif
    73108    }
    74109#endif
     
    158193    }
    159194
     195    exitTcl(interp);
     196    interp = NULL;
     197
    160198    delete g_renderer;
     199    g_renderer = NULL;
    161200
    162201    TRACE("Exiting VTKVis Server");
  • branches/blt4/packages/vizservers/vtkvis/RpVtkRenderer.cpp

    r2215 r2302  
    99#include <cstring>
    1010#include <cassert>
     11
     12#include <GL/gl.h>
     13
     14#ifdef WANT_TRACE
     15#include <sys/time.h>
     16#endif
    1117
    1218#include <vtkMath.h>
     
    3137#include <vtkLookupTable.h>
    3238#include <vtkTextProperty.h>
     39#include <vtkOpenGLRenderWindow.h>
    3340
    3441#include "RpVtkRenderer.h"
    3542#include "ColorMap.h"
    3643#include "Trace.h"
     44
     45#define ELAPSED_TIME(t1, t2) \
     46    ((t1).tv_sec == (t2).tv_sec ? (((t2).tv_usec - (t1).tv_usec)/1.0e+3f) : \
     47     (((t2).tv_sec - (t1).tv_sec))*1.0e+3f + (float)((t2).tv_usec - (t1).tv_usec)/1.0e+3f)
    3748
    3849using namespace Rappture::VtkVis;
     
    4455    _cameraZoomRatio(1),
    4556    _useCumulativeRange(true),
    46     _cumulativeRangeOnlyVisible(false)
     57    _cumulativeRangeOnlyVisible(false),
     58    _cameraMode(PERSPECTIVE)
    4759{
    4860    _bgColor[0] = 0;
     
    5466    _cumulativeDataRange[1] = 1.0;
    5567    // clipping planes to prevent overdrawing axes
    56     _clippingPlanes = vtkSmartPointer<vtkPlaneCollection>::New();
     68    _activeClipPlanes = vtkSmartPointer<vtkPlaneCollection>::New();
    5769    // bottom
    58     vtkSmartPointer<vtkPlane> plane0 = vtkSmartPointer<vtkPlane>::New();
    59     plane0->SetNormal(0, 1, 0);
    60     plane0->SetOrigin(0, 0, 0);
    61     _clippingPlanes->AddItem(plane0);
     70    _clipPlanes[0] = vtkSmartPointer<vtkPlane>::New();
     71    _clipPlanes[0]->SetNormal(0, 1, 0);
     72    _clipPlanes[0]->SetOrigin(0, 0, 0);
     73    if (_cameraMode == IMAGE)
     74        _activeClipPlanes->AddItem(_clipPlanes[0]);
    6275    // left
    63     vtkSmartPointer<vtkPlane> plane1 = vtkSmartPointer<vtkPlane>::New();
    64     plane1->SetNormal(1, 0, 0);
    65     plane1->SetOrigin(0, 0, 0);
    66     _clippingPlanes->AddItem(plane1);
    67    // top
    68     vtkSmartPointer<vtkPlane> plane2 = vtkSmartPointer<vtkPlane>::New();
    69     plane2->SetNormal(0, -1, 0);
    70     plane2->SetOrigin(0, 1, 0);
    71     _clippingPlanes->AddItem(plane2);
     76    _clipPlanes[1] = vtkSmartPointer<vtkPlane>::New();
     77    _clipPlanes[1]->SetNormal(1, 0, 0);
     78    _clipPlanes[1]->SetOrigin(0, 0, 0);
     79    if (_cameraMode == IMAGE)
     80        _activeClipPlanes->AddItem(_clipPlanes[1]);
     81    // top
     82    _clipPlanes[2] = vtkSmartPointer<vtkPlane>::New();
     83    _clipPlanes[2]->SetNormal(0, -1, 0);
     84    _clipPlanes[2]->SetOrigin(0, 1, 0);
     85    if (_cameraMode == IMAGE)
     86        _activeClipPlanes->AddItem(_clipPlanes[2]);
    7287    // right
    73     vtkSmartPointer<vtkPlane> plane3 = vtkSmartPointer<vtkPlane>::New();
    74     plane3->SetNormal(-1, 0, 0);
    75     plane3->SetOrigin(1, 0, 0);
    76     _clippingPlanes->AddItem(plane3);
     88    _clipPlanes[3] = vtkSmartPointer<vtkPlane>::New();
     89    _clipPlanes[3]->SetNormal(-1, 0, 0);
     90    _clipPlanes[3]->SetOrigin(1, 0, 0);
     91    if (_cameraMode == IMAGE)
     92        _activeClipPlanes->AddItem(_clipPlanes[3]);
    7793    _renderer = vtkSmartPointer<vtkRenderer>::New();
    7894    _renderer->LightFollowCameraOn();
    79     _cameraMode = PERSPECTIVE;
    8095    initAxes();
    8196    initCamera();
    8297    storeCameraOrientation();
    8398    _renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
     99#ifdef USE_OFFSCREEN_RENDERING
    84100    _renderWindow->DoubleBufferOff();
    85     //_renderWindow->BordersOff();
     101    _renderWindow->OffScreenRenderingOn();
     102#else
     103    _renderWindow->SwapBuffersOff();
     104#endif
    86105    _renderWindow->SetSize(_windowWidth, _windowHeight);
    87     _renderWindow->OffScreenRenderingOn();
     106    // Next 2 options needed to support depth peeling
     107    _renderWindow->SetAlphaBitPlanes(1);
     108    _renderWindow->SetMultiSamples(0);
     109    _renderer->SetMaximumNumberOfPeels(100);
     110    _renderer->SetUseDepthPeeling(1);
    88111    _renderWindow->AddRenderer(_renderer);
    89     addColorMap("default", ColorMap::createDefault());
     112    addColorMap("default", ColorMap::getDefault());
     113    addColorMap("volumeDefault", ColorMap::getVolumeDefault());
    90114}
    91115
    92116Renderer::~Renderer()
    93117{
     118    TRACE("Enter");
     119    TRACE("Deleting Contour2Ds");
     120    for (Contour2DHashmap::iterator itr = _contour2Ds.begin();
     121             itr != _contour2Ds.end(); ++itr) {
     122        delete itr->second;
     123    }
     124    _contour2Ds.clear();
     125    TRACE("Deleting Contour3Ds");
     126    for (Contour3DHashmap::iterator itr = _contour3Ds.begin();
     127             itr != _contour3Ds.end(); ++itr) {
     128        delete itr->second;
     129    }
     130    _contour3Ds.clear();
     131    TRACE("Deleting Glyphs");
     132    for (GlyphsHashmap::iterator itr = _glyphs.begin();
     133             itr != _glyphs.end(); ++itr) {
     134        delete itr->second;
     135    }
     136    _glyphs.clear();
     137    TRACE("Deleting HeightMaps");
     138    for (HeightMapHashmap::iterator itr = _heightMaps.begin();
     139             itr != _heightMaps.end(); ++itr) {
     140        delete itr->second;
     141    }
     142    _heightMaps.clear();
     143    TRACE("Deleting PolyDatas");
     144    for (PolyDataHashmap::iterator itr = _polyDatas.begin();
     145             itr != _polyDatas.end(); ++itr) {
     146        delete itr->second;
     147    }
     148    _polyDatas.clear();
     149    TRACE("Deleting PseudoColors");
     150    for (PseudoColorHashmap::iterator itr = _pseudoColors.begin();
     151             itr != _pseudoColors.end(); ++itr) {
     152        delete itr->second;
     153    }
     154    _pseudoColors.clear();
     155    TRACE("Deleting Volumes");
     156    for (VolumeHashmap::iterator itr = _volumes.begin();
     157             itr != _volumes.end(); ++itr) {
     158        delete itr->second;
     159    }
     160    _volumes.clear();
     161    TRACE("Deleting ColorMaps");
     162    // Delete color maps and data sets last in case references still
     163    // exist
    94164    for (ColorMapHashmap::iterator itr = _colorMaps.begin();
    95165             itr != _colorMaps.end(); ++itr) {
     
    97167    }
    98168    _colorMaps.clear();
    99     for (PseudoColorHashmap::iterator itr = _pseudoColors.begin();
    100              itr != _pseudoColors.end(); ++itr) {
    101         delete itr->second;
    102     }
    103     _pseudoColors.clear();
    104     for (Contour2DHashmap::iterator itr = _contours.begin();
    105              itr != _contours.end(); ++itr) {
    106         delete itr->second;
    107     }
    108     _contours.clear();
    109     for (PolyDataHashmap::iterator itr = _polyDatas.begin();
    110              itr != _polyDatas.end(); ++itr) {
    111         delete itr->second;
    112     }
    113     _polyDatas.clear();
     169    TRACE("Deleting DataSets");
    114170    for (DataSetHashmap::iterator itr = _dataSets.begin();
    115171             itr != _dataSets.end(); ++itr) {
     
    117173    }
    118174    _dataSets.clear();
     175    TRACE("Leave");
    119176}
    120177
     
    123180 *
    124181 * This just adds the DataSet to the Renderer's list of data sets.
    125  * In order to render the data, a PseudoColor or Contour2D must
    126  * be added to the Renderer.
     182 * In order to render the data, a graphics object using the data
     183 * set must be added to the Renderer.
    127184 */
    128185void Renderer::addDataSet(const DataSetId& id)
     
    136193
    137194/**
     195 * \brief Remove the Contour2D isolines for the specified DataSet
     196 *
     197 * The underlying Contour2D is deleted, freeing its memory
     198 */
     199void Renderer::deleteContour2D(const DataSetId& id)
     200{
     201    Contour2DHashmap::iterator itr;
     202
     203    bool doAll = false;
     204
     205    if (id.compare("all") == 0) {
     206        itr = _contour2Ds.begin();
     207        doAll = true;
     208    } else {
     209        itr = _contour2Ds.find(id);
     210    }
     211    if (itr == _contour2Ds.end()) {
     212        ERROR("Contour2D not found: %s", id.c_str());
     213        return;
     214    }
     215
     216    TRACE("Deleting Contour2Ds for %s", id.c_str());
     217
     218    do {
     219        Contour2D *contour = itr->second;
     220        if (contour->getProp())
     221            _renderer->RemoveViewProp(contour->getProp());
     222        delete contour;
     223
     224        itr = _contour2Ds.erase(itr);
     225    } while (doAll && itr != _contour2Ds.end());
     226
     227    _needsRedraw = true;
     228}
     229
     230/**
     231 * \brief Remove the Contour3D isosurfaces for the specified DataSet
     232 *
     233 * The underlying Contour3D is deleted, freeing its memory
     234 */
     235void Renderer::deleteContour3D(const DataSetId& id)
     236{
     237    Contour3DHashmap::iterator itr;
     238
     239    bool doAll = false;
     240
     241    if (id.compare("all") == 0) {
     242        itr = _contour3Ds.begin();
     243        doAll = true;
     244    } else {
     245        itr = _contour3Ds.find(id);
     246    }
     247    if (itr == _contour3Ds.end()) {
     248        ERROR("Contour3D not found: %s", id.c_str());
     249        return;
     250    }
     251
     252    TRACE("Deleting Contour3Ds for %s", id.c_str());
     253
     254    do {
     255        Contour3D *contour = itr->second;
     256        if (contour->getProp())
     257            _renderer->RemoveViewProp(contour->getProp());
     258        delete contour;
     259
     260        itr = _contour3Ds.erase(itr);
     261    } while (doAll && itr != _contour3Ds.end());
     262
     263    _needsRedraw = true;
     264}
     265
     266/**
     267 * \brief Remove the Glyphs for the specified DataSet
     268 *
     269 * The underlying Glyphs is deleted, freeing its memory
     270 */
     271void Renderer::deleteGlyphs(const DataSetId& id)
     272{
     273    GlyphsHashmap::iterator itr;
     274
     275    bool doAll = false;
     276
     277    if (id.compare("all") == 0) {
     278        itr = _glyphs.begin();
     279        doAll = true;
     280    } else {
     281        itr = _glyphs.find(id);
     282    }
     283    if (itr == _glyphs.end()) {
     284        ERROR("Glyphs not found: %s", id.c_str());
     285        return;
     286    }
     287
     288    TRACE("Deleting Glyphs for %s", id.c_str());
     289
     290    do {
     291        Glyphs *glyphs = itr->second;
     292        if (glyphs->getProp())
     293            _renderer->RemoveViewProp(glyphs->getProp());
     294        delete glyphs;
     295
     296        itr = _glyphs.erase(itr);
     297    } while (doAll && itr != _glyphs.end());
     298
     299    _needsRedraw = true;
     300}
     301
     302/**
     303 * \brief Remove the HeightMap for the specified DataSet
     304 *
     305 * The underlying HeightMap is deleted, freeing its memory
     306 */
     307void Renderer::deleteHeightMap(const DataSetId& id)
     308{
     309    HeightMapHashmap::iterator itr;
     310
     311    bool doAll = false;
     312
     313    if (id.compare("all") == 0) {
     314        itr = _heightMaps.begin();
     315        doAll = true;
     316    } else {
     317        itr = _heightMaps.find(id);
     318    }
     319    if (itr == _heightMaps.end()) {
     320        ERROR("HeightMap not found: %s", id.c_str());
     321        return;
     322    }
     323
     324    TRACE("Deleting HeightMaps for %s", id.c_str());
     325
     326    do {
     327        HeightMap *hmap = itr->second;
     328        if (hmap->getProp())
     329            _renderer->RemoveViewProp(hmap->getProp());
     330        delete hmap;
     331
     332        itr = _heightMaps.erase(itr);
     333    } while (doAll && itr != _heightMaps.end());
     334
     335    _needsRedraw = true;
     336}
     337
     338/**
     339 * \brief Remove the PolyData mesh for the specified DataSet
     340 *
     341 * The underlying PolyData is deleted, freeing its memory
     342 */
     343void Renderer::deletePolyData(const DataSetId& id)
     344{
     345    PolyDataHashmap::iterator itr;
     346
     347    bool doAll = false;
     348
     349    if (id.compare("all") == 0) {
     350        itr = _polyDatas.begin();
     351        doAll = true;
     352    } else {
     353        itr = _polyDatas.find(id);
     354    }
     355    if (itr == _polyDatas.end()) {
     356        ERROR("PolyData not found: %s", id.c_str());
     357        return;
     358    }
     359
     360    TRACE("Deleting PolyDatas for %s", id.c_str());
     361
     362    do {
     363        PolyData *polyData = itr->second;
     364        if (polyData->getProp())
     365            _renderer->RemoveViewProp(polyData->getProp());
     366        delete polyData;
     367
     368        itr = _polyDatas.erase(itr);
     369    } while (doAll && itr != _polyDatas.end());
     370
     371    _needsRedraw = true;
     372}
     373
     374/**
    138375 * \brief Remove the PseudoColor mapping for the specified DataSet
    139376 *
     
    161398    do  {
    162399        PseudoColor *ps = itr->second;
    163         if (ps->getActor())
    164             _renderer->RemoveActor(ps->getActor());
     400        if (ps->getProp())
     401            _renderer->RemoveViewProp(ps->getProp());
    165402        delete ps;
    166403
    167         _pseudoColors.erase(itr);
    168     } while (doAll && ++itr != _pseudoColors.end());
    169 
    170     _needsRedraw = true;
    171 }
    172 
    173 /**
    174  * \brief Remove the Contour2D isolines for the specified DataSet
     404        itr = _pseudoColors.erase(itr);
     405    } while (doAll && itr != _pseudoColors.end());
     406
     407    _needsRedraw = true;
     408}
     409
     410/**
     411 * \brief Remove the Volume for the specified DataSet
    175412 *
    176  * The underlying Contour2D is deleted, freeing its memory
    177  */
    178 void Renderer::deleteContour2D(const DataSetId& id)
    179 {
    180     Contour2DHashmap::iterator itr;
    181 
    182     bool doAll = false;
    183 
    184     if (id.compare("all") == 0) {
    185         itr = _contours.begin();
    186         doAll = true;
    187     } else {
    188         itr = _contours.find(id);
    189     }
    190     if (itr == _contours.end()) {
    191         ERROR("Contour2D not found: %s", id.c_str());
    192         return;
    193     }
    194 
    195     TRACE("Deleting Contour2Ds for %s", id.c_str());
    196 
    197     do {
    198         Contour2D *contour = itr->second;
    199         if (contour->getActor())
    200             _renderer->RemoveActor(contour->getActor());
    201         delete contour;
    202 
    203         _contours.erase(itr);
    204     } while (doAll && ++itr != _contours.end());
    205 
    206     _needsRedraw = true;
    207 }
    208 
    209 /**
    210  * \brief Remove the PolyData mesh for the specified DataSet
    211  *
    212  * The underlying PolyData is deleted, freeing its memory
    213  */
    214 void Renderer::deletePolyData(const DataSetId& id)
    215 {
    216     PolyDataHashmap::iterator itr;
    217    
    218     bool doAll = false;
    219 
    220     if (id.compare("all") == 0) {
    221         itr = _polyDatas.begin();
    222         doAll = true;
    223     } else {
    224         itr = _polyDatas.find(id);
    225     }
    226     if (itr == _polyDatas.end()) {
    227         ERROR("PolyData not found: %s", id.c_str());
    228         return;
    229     }
    230 
    231     TRACE("Deleting PolyDatas for %s", id.c_str());
    232 
    233     do {
    234         PolyData *polyData = itr->second;
    235         if (polyData->getActor())
    236             _renderer->RemoveActor(polyData->getActor());
    237         delete polyData;
    238 
    239         _polyDatas.erase(itr);
    240     } while (doAll && ++itr != _polyDatas.end());
     413 * The underlying Volume is deleted, freeing its memory
     414 */
     415void Renderer::deleteVolume(const DataSetId& id)
     416{
     417    VolumeHashmap::iterator itr;
     418
     419    bool doAll = false;
     420
     421    if (id.compare("all") == 0) {
     422        itr = _volumes.begin();
     423        doAll = true;
     424    } else {
     425        itr = _volumes.find(id);
     426    }
     427    if (itr == _volumes.end()) {
     428        ERROR("Volume not found: %s", id.c_str());
     429        return;
     430    }
     431
     432    TRACE("Deleting Volumes for %s", id.c_str());
     433
     434    do {
     435        Volume *volume = itr->second;
     436        if (volume->getProp())
     437            _renderer->RemoveViewProp(volume->getProp());
     438        delete volume;
     439
     440        itr = _volumes.erase(itr);
     441    } while (doAll && itr != _volumes.end());
    241442
    242443    _needsRedraw = true;
     
    246447 * \brief Remove the specified DataSet and associated rendering objects
    247448 *
    248  * The underlying DataSet and any associated Contour2D and PseudoColor
     449 * The underlying DataSet and any associated graphics
    249450 * objects are deleted, freeing the memory used.
    250451 */
     
    269470        TRACE("Deleting dataset %s", itr->second->getName().c_str());
    270471
     472        deleteContour2D(itr->second->getName());
     473        deleteContour3D(itr->second->getName());
     474        deleteGlyphs(itr->second->getName());
     475        deleteHeightMap(itr->second->getName());
     476        deletePolyData(itr->second->getName());
    271477        deletePseudoColor(itr->second->getName());
    272         deleteContour2D(itr->second->getName());
    273         deletePolyData(itr->second->getName());
     478        deleteVolume(itr->second->getName());
    274479   
    275480        TRACE("After deleting graphics objects");
    276481
    277482        delete itr->second;
    278         _dataSets.erase(itr);
    279     } while (doAll && ++itr != _dataSets.end());
     483        itr = _dataSets.erase(itr);
     484    } while (doAll && itr != _dataSets.end());
    280485
    281486    // Update cumulative data range
     
    358563        if (_renderer->HasViewProp(_cubeAxesActor)) {
    359564            TRACE("Removing 3D axes");
    360             _renderer->RemoveActor(_cubeAxesActor);
     565            _renderer->RemoveViewProp(_cubeAxesActor);
    361566        }
    362567        if (!_renderer->HasViewProp(_cubeAxesActor2D)) {
    363568            TRACE("Adding 2D axes");
    364             _renderer->AddActor(_cubeAxesActor2D);
     569            _renderer->AddViewProp(_cubeAxesActor2D);
    365570        }
    366571    } else {
    367572        if (_renderer->HasViewProp(_cubeAxesActor2D)) {
    368573            TRACE("Removing 2D axes");
    369             _renderer->RemoveActor(_cubeAxesActor2D);
     574            _renderer->RemoveViewProp(_cubeAxesActor2D);
    370575        }
    371576        if (!_renderer->HasViewProp(_cubeAxesActor)) {
    372577            TRACE("Adding 3D axes");
    373             _renderer->AddActor(_cubeAxesActor);
     578            _renderer->AddViewProp(_cubeAxesActor);
    374579        }
    375580        double bounds[6];
    376         collectBounds(bounds, true);
     581        collectBounds(bounds, false);
    377582        _cubeAxesActor->SetBounds(bounds);
    378583    }
     
    441646    if (_cameraMode == IMAGE) {
    442647        if (!_renderer->HasViewProp(_cubeAxesActor2D))
    443             _renderer->AddActor(_cubeAxesActor2D);
     648            _renderer->AddViewProp(_cubeAxesActor2D);
    444649    } else {
    445650        if (!_renderer->HasViewProp(_cubeAxesActor))
    446             _renderer->AddActor(_cubeAxesActor);
    447     }
     651            _renderer->AddViewProp(_cubeAxesActor);
     652    }
     653}
     654
     655/**
     656 * \brief Set Fly mode of axes
     657 */
     658void Renderer::setAxesFlyMode(AxesFlyMode mode)
     659{
     660    if (_cubeAxesActor == NULL)
     661        initAxes();
     662    switch (mode) {
     663    case FLY_STATIC_EDGES:
     664        _cubeAxesActor->SetFlyModeToStaticEdges();
     665        break;
     666    case FLY_STATIC_TRIAD:
     667        _cubeAxesActor->SetFlyModeToStaticTriad();
     668        break;
     669    case FLY_OUTER_EDGES:
     670        _cubeAxesActor->SetFlyModeToOuterEdges();
     671        break;
     672    case FLY_FURTHEST_TRIAD:
     673        _cubeAxesActor->SetFlyModeToFurthestTriad();
     674        break;
     675    case FLY_CLOSEST_TRIAD:
     676    default:
     677        _cubeAxesActor->SetFlyModeToClosestTriad();
     678        break;
     679    }
     680    _needsRedraw = true;
    448681}
    449682
     
    656889        // TODO: Check if color map is used in PseudoColors?
    657890        delete itr->second;
    658         _colorMaps.erase(itr);
    659     } while (doAll && ++itr != _colorMaps.end());
     891        itr = _colorMaps.erase(itr);
     892    } while (doAll && itr != _colorMaps.end());
    660893}
    661894
     
    678911    if (_legendRenderWindow == NULL) {
    679912        _legendRenderWindow = vtkSmartPointer<vtkRenderWindow>::New();
     913#ifdef USE_OFFSCREEN_RENDERING
    680914        _legendRenderWindow->DoubleBufferOff();
    681915        _legendRenderWindow->OffScreenRenderingOn();
     916#endif
    682917    }
    683918
     
    693928        _scalarBarActor = vtkSmartPointer<vtkScalarBarActor>::New();
    694929        _scalarBarActor->UseOpacityOn();
    695         _legendRenderer->AddActor(_scalarBarActor);
     930        _legendRenderer->AddViewProp(_scalarBarActor);
    696931    }
    697932
     
    731966    _legendRenderWindow->Render();
    732967
    733     _legendRenderWindow->GetPixelData(0, 0, width-1, height-1, 1, imgData);
     968#ifdef RENDER_TARGA
     969    _legendRenderWindow->MakeCurrent();
     970    // Must clear previous errors first.
     971    while (glGetError() != GL_NO_ERROR){
     972        ;
     973    }
     974    int bytesPerPixel = TARGA_BYTES_PER_PIXEL;
     975    int size = bytesPerPixel * width * height;
     976
     977    if (imgData->GetMaxId() + 1 != size)
     978    {
     979        imgData->SetNumberOfComponents(bytesPerPixel);
     980        imgData->SetNumberOfValues(size);
     981    }
     982    glDisable(GL_TEXTURE_2D);
     983    glReadBuffer(static_cast<GLenum>(vtkOpenGLRenderWindow::SafeDownCast(_renderWindow)->GetFrontLeftBuffer()));
     984    glPixelStorei(GL_PACK_ALIGNMENT, 1);
     985    if (bytesPerPixel == 4) {
     986        glReadPixels(0, 0, width, height, GL_BGRA,
     987                     GL_UNSIGNED_BYTE, imgData->GetPointer(0));
     988    } else {
     989        glReadPixels(0, 0, width, height, GL_BGR,
     990                     GL_UNSIGNED_BYTE, imgData->GetPointer(0));
     991    }
     992    if (glGetError() != GL_NO_ERROR) {
     993        ERROR("glReadPixels");
     994    }
     995#else
     996    _legendRenderWindow->GetPixelData(0, 0, width-1, height-1,
     997                                      !_legendRenderWindow->GetDoubleBuffer(),
     998                                      imgData);
     999#endif
    7341000    return true;
    7351001}
    7361002
    7371003/**
    738  * \brief Create a new PseudoColor rendering for the specified DataSet
    739  */
    740 void Renderer::addPseudoColor(const DataSetId& id)
     1004 * \brief Create a new Contour2D and associate it with the named DataSet
     1005 */
     1006void Renderer::addContour2D(const DataSetId& id)
    7411007{
    7421008    DataSetHashmap::iterator itr;
     
    7581024        const DataSetId& dsID = ds->getName();
    7591025
    760         if (getPseudoColor(dsID)) {
    761             WARN("Replacing existing pseudocolor %s", dsID.c_str());
    762             deletePseudoColor(dsID);
    763         }
    764         PseudoColor *pc = new PseudoColor();
    765         _pseudoColors[dsID] = pc;
    766 
    767         pc->setDataSet(ds);
     1026        if (getContour2D(dsID)) {
     1027            WARN("Replacing existing contour2d %s", dsID.c_str());
     1028            deleteContour2D(dsID);
     1029        }
     1030
     1031        Contour2D *contour = new Contour2D();
     1032        _contour2Ds[dsID] = contour;
     1033
     1034        contour->setDataSet(ds);
     1035
     1036        _renderer->AddViewProp(contour->getProp());
     1037    } while (doAll && ++itr != _dataSets.end());
     1038
     1039    initCamera();
     1040    _needsRedraw = true;
     1041}
     1042
     1043/**
     1044 * \brief Get the Contour2D associated with a named DataSet
     1045 */
     1046Contour2D *Renderer::getContour2D(const DataSetId& id)
     1047{
     1048    Contour2DHashmap::iterator itr = _contour2Ds.find(id);
     1049
     1050    if (itr == _contour2Ds.end()) {
     1051        TRACE("Contour2D not found: %s", id.c_str());
     1052        return NULL;
     1053    } else
     1054        return itr->second;
     1055}
     1056
     1057/**
     1058 * \brief Set the number of equally spaced contour isolines for the given DataSet
     1059 */
     1060void Renderer::setContour2DContours(const DataSetId& id, int numContours)
     1061{
     1062    Contour2DHashmap::iterator itr;
     1063
     1064    bool doAll = false;
     1065
     1066    if (id.compare("all") == 0) {
     1067        itr = _contour2Ds.begin();
     1068        doAll = true;
     1069    } else {
     1070        itr = _contour2Ds.find(id);
     1071    }
     1072    if (itr == _contour2Ds.end()) {
     1073        ERROR("Contour2D not found: %s", id.c_str());
     1074        return;
     1075    }
     1076
     1077    do {
     1078        if (_useCumulativeRange) {
     1079            itr->second->setContours(numContours, _cumulativeDataRange);
     1080        } else {
     1081            itr->second->setContours(numContours);
     1082        }
     1083    } while (doAll && ++itr != _contour2Ds.end());
     1084
     1085    _needsRedraw = true;
     1086}
     1087
     1088/**
     1089 * \brief Set a list of isovalues for the given DataSet
     1090 */
     1091void Renderer::setContour2DContourList(const DataSetId& id, const std::vector<double>& contours)
     1092{
     1093    Contour2DHashmap::iterator itr;
     1094
     1095    bool doAll = false;
     1096
     1097    if (id.compare("all") == 0) {
     1098        itr = _contour2Ds.begin();
     1099        doAll = true;
     1100    } else {
     1101        itr = _contour2Ds.find(id);
     1102    }
     1103    if (itr == _contour2Ds.end()) {
     1104        ERROR("Contour2D not found: %s", id.c_str());
     1105        return;
     1106    }
     1107
     1108    do {
     1109        itr->second->setContourList(contours);
     1110    } while (doAll && ++itr != _contour2Ds.end());
     1111
     1112     _needsRedraw = true;
     1113}
     1114
     1115/**
     1116 * \brief Set opacity of contour lines for the given DataSet
     1117 */
     1118void Renderer::setContour2DOpacity(const DataSetId& id, double opacity)
     1119{
     1120    Contour2DHashmap::iterator itr;
     1121
     1122    bool doAll = false;
     1123
     1124    if (id.compare("all") == 0) {
     1125        itr = _contour2Ds.begin();
     1126        doAll = true;
     1127    } else {
     1128        itr = _contour2Ds.find(id);
     1129    }
     1130    if (itr == _contour2Ds.end()) {
     1131        ERROR("Contour2D not found: %s", id.c_str());
     1132        return;
     1133    }
     1134
     1135    do {
     1136        itr->second->setOpacity(opacity);
     1137    } while (doAll && ++itr != _contour2Ds.end());
     1138
     1139    _needsRedraw = true;
     1140}
     1141
     1142/**
     1143 * \brief Turn on/off rendering contour lines for the given DataSet
     1144 */
     1145void Renderer::setContour2DVisibility(const DataSetId& id, bool state)
     1146{
     1147    Contour2DHashmap::iterator itr;
     1148
     1149    bool doAll = false;
     1150
     1151    if (id.compare("all") == 0) {
     1152        itr = _contour2Ds.begin();
     1153        doAll = true;
     1154    } else {
     1155        itr = _contour2Ds.find(id);
     1156    }
     1157    if (itr == _contour2Ds.end()) {
     1158        ERROR("Contour2D not found: %s", id.c_str());
     1159        return;
     1160    }
     1161
     1162    do {
     1163        itr->second->setVisibility(state);
     1164    } while (doAll && ++itr != _contour2Ds.end());
     1165
     1166    _needsRedraw = true;
     1167}
     1168
     1169/**
     1170 * \brief Set the RGB isoline color for the specified DataSet
     1171 */
     1172void Renderer::setContour2DEdgeColor(const DataSetId& id, float color[3])
     1173{
     1174    Contour2DHashmap::iterator itr;
     1175
     1176    bool doAll = false;
     1177
     1178    if (id.compare("all") == 0) {
     1179        itr = _contour2Ds.begin();
     1180        doAll = true;
     1181    } else {
     1182        itr = _contour2Ds.find(id);
     1183    }
     1184    if (itr == _contour2Ds.end()) {
     1185        ERROR("Contour2D not found: %s", id.c_str());
     1186        return;
     1187    }
     1188
     1189    do {
     1190        itr->second->setEdgeColor(color);
     1191    } while (doAll && ++itr != _contour2Ds.end());
     1192
     1193    _needsRedraw = true;
     1194}
     1195
     1196/**
     1197 * \brief Set the isoline width for the specified DataSet (may be a no-op)
     1198 *
     1199 * If the OpenGL implementation/hardware does not support wide lines,
     1200 * this function may not have an effect.
     1201 */
     1202void Renderer::setContour2DEdgeWidth(const DataSetId& id, float edgeWidth)
     1203{
     1204    Contour2DHashmap::iterator itr;
     1205
     1206    bool doAll = false;
     1207
     1208    if (id.compare("all") == 0) {
     1209        itr = _contour2Ds.begin();
     1210        doAll = true;
     1211    } else {
     1212        itr = _contour2Ds.find(id);
     1213    }
     1214    if (itr == _contour2Ds.end()) {
     1215        ERROR("Contour2D not found: %s", id.c_str());
     1216        return;
     1217    }
     1218
     1219    do {
     1220        itr->second->setEdgeWidth(edgeWidth);
     1221    } while (doAll && ++itr != _contour2Ds.end());
     1222
     1223    _needsRedraw = true;
     1224}
     1225
     1226/**
     1227 * \brief Turn contour lighting on/off for the specified DataSet
     1228 */
     1229void Renderer::setContour2DLighting(const DataSetId& id, bool state)
     1230{
     1231    Contour2DHashmap::iterator itr;
     1232
     1233    bool doAll = false;
     1234
     1235    if (id.compare("all") == 0) {
     1236        itr = _contour2Ds.begin();
     1237        doAll = true;
     1238    } else {
     1239        itr = _contour2Ds.find(id);
     1240    }
     1241    if (itr == _contour2Ds.end()) {
     1242        ERROR("Contour2D not found: %s", id.c_str());
     1243        return;
     1244    }
     1245
     1246    do {
     1247        itr->second->setLighting(state);
     1248    } while (doAll && ++itr != _contour2Ds.end());
     1249    _needsRedraw = true;
     1250}
     1251
     1252/**
     1253 * \brief Create a new Contour3D and associate it with the named DataSet
     1254 */
     1255void Renderer::addContour3D(const DataSetId& id)
     1256{
     1257    DataSetHashmap::iterator itr;
     1258
     1259    bool doAll = false;
     1260
     1261    if (id.compare("all") == 0) {
     1262        itr = _dataSets.begin();
     1263    } else {
     1264        itr = _dataSets.find(id);
     1265    }
     1266    if (itr == _dataSets.end()) {
     1267        ERROR("Unknown dataset %s", id.c_str());
     1268        return;
     1269    }
     1270
     1271    do {
     1272        DataSet *ds = itr->second;
     1273        const DataSetId& dsID = ds->getName();
     1274
     1275        if (getContour3D(dsID)) {
     1276            WARN("Replacing existing contour3d %s", dsID.c_str());
     1277            deleteContour3D(dsID);
     1278        }
     1279
     1280        Contour3D *contour = new Contour3D();
     1281        _contour3Ds[dsID] = contour;
     1282
     1283        contour->setDataSet(ds);
    7681284
    7691285        // Use the default color map
     
    7791295        }
    7801296
    781         pc->setLookupTable(lut);
    782 
    783         _renderer->AddActor(pc->getActor());
     1297        contour->setLookupTable(lut);
     1298
     1299        _renderer->AddViewProp(contour->getProp());
    7841300    } while (doAll && ++itr != _dataSets.end());
    7851301
     1302    if (_cameraMode == IMAGE)
     1303        setCameraMode(PERSPECTIVE);
    7861304    initCamera();
    7871305    _needsRedraw = true;
     
    7891307
    7901308/**
    791  * \brief Get the PseudoColor associated with the specified DataSet
    792  */
    793 PseudoColor *Renderer::getPseudoColor(const DataSetId& id)
    794 {
    795     PseudoColorHashmap::iterator itr = _pseudoColors.find(id);
    796 
    797     if (itr == _pseudoColors.end()) {
    798         TRACE("PseudoColor not found: %s", id.c_str());
     1309 * \brief Get the Contour3D associated with a named DataSet
     1310 */
     1311Contour3D *Renderer::getContour3D(const DataSetId& id)
     1312{
     1313    Contour3DHashmap::iterator itr = _contour3Ds.find(id);
     1314
     1315    if (itr == _contour3Ds.end()) {
     1316        TRACE("Contour3D not found: %s", id.c_str());
    7991317        return NULL;
    8001318    } else
     
    8031321
    8041322/**
    805  * \brief Associate an existing named color map with a DataSet
    806  */
    807 void Renderer::setPseudoColorColorMap(const DataSetId& id, const ColorMapId& colorMapId)
    808 {
    809     PseudoColorHashmap::iterator itr;
    810 
    811     bool doAll = false;
    812 
    813     if (id.compare("all") == 0) {
    814         itr = _pseudoColors.begin();
    815         doAll = true;
    816     } else {
    817         itr = _pseudoColors.find(id);
    818     }
    819 
    820     if (itr == _pseudoColors.end()) {
    821         ERROR("PseudoColor not found: %s", id.c_str());
     1323 * \brief Set the number of equally spaced isosurfaces for the given DataSet
     1324 */
     1325void Renderer::setContour3DContours(const DataSetId& id, int numContours)
     1326{
     1327    Contour3DHashmap::iterator itr;
     1328
     1329    bool doAll = false;
     1330
     1331    if (id.compare("all") == 0) {
     1332        itr = _contour3Ds.begin();
     1333        doAll = true;
     1334    } else {
     1335        itr = _contour3Ds.find(id);
     1336    }
     1337    if (itr == _contour3Ds.end()) {
     1338        ERROR("Contour3D not found: %s", id.c_str());
     1339        return;
     1340    }
     1341
     1342    do {
     1343        if (_useCumulativeRange) {
     1344            itr->second->setContours(numContours, _cumulativeDataRange);
     1345        } else {
     1346            itr->second->setContours(numContours);
     1347        }
     1348    } while (doAll && ++itr != _contour3Ds.end());
     1349
     1350    initCamera();
     1351    _needsRedraw = true;
     1352}
     1353
     1354/**
     1355 * \brief Set a list of isovalues for the given DataSet
     1356 */
     1357void Renderer::setContour3DContourList(const DataSetId& id, const std::vector<double>& contours)
     1358{
     1359    Contour3DHashmap::iterator itr;
     1360
     1361    bool doAll = false;
     1362
     1363    if (id.compare("all") == 0) {
     1364        itr = _contour3Ds.begin();
     1365        doAll = true;
     1366    } else {
     1367        itr = _contour3Ds.find(id);
     1368    }
     1369    if (itr == _contour3Ds.end()) {
     1370        ERROR("Contour3D not found: %s", id.c_str());
     1371        return;
     1372    }
     1373
     1374    do {
     1375        itr->second->setContourList(contours);
     1376    } while (doAll && ++itr != _contour3Ds.end());
     1377
     1378    initCamera();
     1379     _needsRedraw = true;
     1380}
     1381
     1382/**
     1383 * \brief Set opacity of isosurfaces for the given DataSet
     1384 */
     1385void Renderer::setContour3DOpacity(const DataSetId& id, double opacity)
     1386{
     1387    Contour3DHashmap::iterator itr;
     1388
     1389    bool doAll = false;
     1390
     1391    if (id.compare("all") == 0) {
     1392        itr = _contour3Ds.begin();
     1393        doAll = true;
     1394    } else {
     1395        itr = _contour3Ds.find(id);
     1396    }
     1397    if (itr == _contour3Ds.end()) {
     1398        ERROR("Contour3D not found: %s", id.c_str());
     1399        return;
     1400    }
     1401
     1402    do {
     1403        itr->second->setOpacity(opacity);
     1404    } while (doAll && ++itr != _contour3Ds.end());
     1405
     1406    _needsRedraw = true;
     1407}
     1408
     1409/**
     1410 * \brief Turn on/off rendering isosurfaces for the given DataSet
     1411 */
     1412void Renderer::setContour3DVisibility(const DataSetId& id, bool state)
     1413{
     1414    Contour3DHashmap::iterator itr;
     1415
     1416    bool doAll = false;
     1417
     1418    if (id.compare("all") == 0) {
     1419        itr = _contour3Ds.begin();
     1420        doAll = true;
     1421    } else {
     1422        itr = _contour3Ds.find(id);
     1423    }
     1424    if (itr == _contour3Ds.end()) {
     1425        ERROR("Contour3D not found: %s", id.c_str());
     1426        return;
     1427    }
     1428
     1429    do {
     1430        itr->second->setVisibility(state);
     1431    } while (doAll && ++itr != _contour3Ds.end());
     1432
     1433    _needsRedraw = true;
     1434}
     1435
     1436/**
     1437 * \brief Associate an existing named color map with a Contour3D for the given
     1438 * DataSet
     1439 */
     1440void Renderer::setContour3DColorMap(const DataSetId& id, const ColorMapId& colorMapId)
     1441{
     1442    Contour3DHashmap::iterator itr;
     1443
     1444    bool doAll = false;
     1445
     1446    if (id.compare("all") == 0) {
     1447        itr = _contour3Ds.begin();
     1448        doAll = true;
     1449    } else {
     1450        itr = _contour3Ds.find(id);
     1451    }
     1452
     1453    if (itr == _contour3Ds.end()) {
     1454        ERROR("Contour3D not found: %s", id.c_str());
    8221455        return;
    8231456    }
     
    8301463
    8311464    do {
    832         TRACE("Set color map: %s for dataset %s", colorMapId.c_str(),
     1465        TRACE("Set Contour3D color map: %s for dataset %s", colorMapId.c_str(),
    8331466              itr->second->getDataSet()->getName().c_str());
    8341467
     
    8501483
    8511484        itr->second->setLookupTable(lut);
    852     } while (doAll && ++itr != _pseudoColors.end());
    853 
    854     _needsRedraw = true;
    855 }
    856 
    857 /**
    858  * \brief Get the color map (vtkLookupTable) for the given DataSet
    859  *
    860  * \return The associated lookup table or NULL if not found
    861  */
    862 vtkLookupTable *Renderer::getPseudoColorColorMap(const DataSetId& id)
    863 {
    864     PseudoColor *pc = getPseudoColor(id);
    865     if (pc)
    866         return pc->getLookupTable();
    867     else
    868         return NULL;
    869 }
    870 
    871 /**
    872  * \brief Set opacity of the PseudoColor for the given DataSet
    873  */
    874 void Renderer::setPseudoColorOpacity(const DataSetId& id, double opacity)
    875 {
    876     PseudoColorHashmap::iterator itr;
    877 
    878     bool doAll = false;
    879 
    880     if (id.compare("all") == 0) {
    881         itr = _pseudoColors.begin();
    882         doAll = true;
    883     } else {
    884         itr = _pseudoColors.find(id);
    885     }
    886 
    887     if (itr == _pseudoColors.end()) {
    888         ERROR("PseudoColor not found: %s", id.c_str());
    889         return;
    890     }
    891 
    892     do {
    893         itr->second->setOpacity(opacity);
    894     } while (doAll && ++itr != _pseudoColors.end());
    895 
    896     _needsRedraw = true;
    897 }
    898 
    899 /**
    900  * \brief Turn on/off rendering of the PseudoColor mapper for the given DataSet
    901  */
    902 void Renderer::setPseudoColorVisibility(const DataSetId& id, bool state)
    903 {
    904     PseudoColorHashmap::iterator itr;
    905 
    906     bool doAll = false;
    907 
    908     if (id.compare("all") == 0) {
    909         itr = _pseudoColors.begin();
    910         doAll = true;
    911     } else {
    912         itr = _pseudoColors.find(id);
    913     }
    914 
    915     if (itr == _pseudoColors.end()) {
    916         ERROR("PseudoColor not found: %s", id.c_str());
    917         return;
    918     }
    919 
    920     do {
    921         itr->second->setVisibility(state);
    922     } while (doAll && ++itr != _pseudoColors.end());
    923 
    924     _needsRedraw = true;
    925 }
    926 
    927 /**
    928  * \brief Set the visibility of polygon edges for the specified DataSet
    929  */
    930 void Renderer::setPseudoColorEdgeVisibility(const DataSetId& id, bool state)
    931 {
    932     PseudoColorHashmap::iterator itr;
    933 
    934     bool doAll = false;
    935 
    936     if (id.compare("all") == 0) {
    937         itr = _pseudoColors.begin();
    938         doAll = true;
    939     } else {
    940         itr = _pseudoColors.find(id);
    941     }
    942 
    943     if (itr == _pseudoColors.end()) {
    944         ERROR("PseudoColor not found: %s", id.c_str());
     1485    } while (doAll && ++itr != _contour3Ds.end());
     1486
     1487    _needsRedraw = true;
     1488}
     1489
     1490/**
     1491 * \brief Set the RGB isosurface color for the specified DataSet
     1492 */
     1493void Renderer::setContour3DColor(const DataSetId& id, float color[3])
     1494{
     1495    Contour3DHashmap::iterator itr;
     1496
     1497    bool doAll = false;
     1498
     1499    if (id.compare("all") == 0) {
     1500        itr = _contour3Ds.begin();
     1501        doAll = true;
     1502    } else {
     1503        itr = _contour3Ds.find(id);
     1504    }
     1505    if (itr == _contour3Ds.end()) {
     1506        ERROR("Contour3D not found: %s", id.c_str());
     1507        return;
     1508    }
     1509
     1510    do {
     1511        itr->second->setColor(color);
     1512    } while (doAll && ++itr != _contour3Ds.end());
     1513    _needsRedraw = true;
     1514}
     1515
     1516/**
     1517 * \brief Turn on/off rendering isosurface edges for the given DataSet
     1518 */
     1519void Renderer::setContour3DEdgeVisibility(const DataSetId& id, bool state)
     1520{
     1521    Contour3DHashmap::iterator itr;
     1522
     1523    bool doAll = false;
     1524
     1525    if (id.compare("all") == 0) {
     1526        itr = _contour3Ds.begin();
     1527        doAll = true;
     1528    } else {
     1529        itr = _contour3Ds.find(id);
     1530    }
     1531    if (itr == _contour3Ds.end()) {
     1532        ERROR("Contour3D not found: %s", id.c_str());
    9451533        return;
    9461534    }
     
    9481536    do {
    9491537        itr->second->setEdgeVisibility(state);
    950     } while (doAll && ++itr != _pseudoColors.end());
    951 
    952     _needsRedraw = true;
    953 }
    954 
    955 /**
    956  * \brief Set the RGB polygon edge color for the specified DataSet
    957  */
    958 void Renderer::setPseudoColorEdgeColor(const DataSetId& id, float color[3])
    959 {
    960     PseudoColorHashmap::iterator itr;
    961 
    962     bool doAll = false;
    963 
    964     if (id.compare("all") == 0) {
    965         itr = _pseudoColors.begin();
    966         doAll = true;
    967     } else {
    968         itr = _pseudoColors.find(id);
    969     }
    970 
    971     if (itr == _pseudoColors.end()) {
    972         ERROR("PseudoColor not found: %s", id.c_str());
     1538    } while (doAll && ++itr != _contour3Ds.end());
     1539
     1540    _needsRedraw = true;
     1541}
     1542
     1543/**
     1544 * \brief Set the RGB isosurface edge color for the specified DataSet
     1545 */
     1546void Renderer::setContour3DEdgeColor(const DataSetId& id, float color[3])
     1547{
     1548    Contour3DHashmap::iterator itr;
     1549
     1550    bool doAll = false;
     1551
     1552    if (id.compare("all") == 0) {
     1553        itr = _contour3Ds.begin();
     1554        doAll = true;
     1555    } else {
     1556        itr = _contour3Ds.find(id);
     1557    }
     1558    if (itr == _contour3Ds.end()) {
     1559        ERROR("Contour3D not found: %s", id.c_str());
    9731560        return;
    9741561    }
     
    9761563    do {
    9771564        itr->second->setEdgeColor(color);
    978     } while (doAll && ++itr != _pseudoColors.end());
    979 
    980     _needsRedraw = true;
    981 }
    982 
    983 /**
    984  * \brief Set the polygon edge width for the specified DataSet (may be a no-op)
     1565    } while (doAll && ++itr != _contour3Ds.end());
     1566
     1567    _needsRedraw = true;
     1568}
     1569
     1570/**
     1571 * \brief Set the isosurface edge width for the specified DataSet (may be a no-op)
    9851572 *
    9861573 * If the OpenGL implementation/hardware does not support wide lines,
    9871574 * this function may not have an effect.
    9881575 */
    989 void Renderer::setPseudoColorEdgeWidth(const DataSetId& id, float edgeWidth)
    990 {
    991     PseudoColorHashmap::iterator itr;
    992 
    993     bool doAll = false;
    994 
    995     if (id.compare("all") == 0) {
    996         itr = _pseudoColors.begin();
    997         doAll = true;
    998     } else {
    999         itr = _pseudoColors.find(id);
    1000     }
    1001 
    1002     if (itr == _pseudoColors.end()) {
    1003         ERROR("PseudoColor not found: %s", id.c_str());
     1576void Renderer::setContour3DEdgeWidth(const DataSetId& id, float edgeWidth)
     1577{
     1578    Contour3DHashmap::iterator itr;
     1579
     1580    bool doAll = false;
     1581
     1582    if (id.compare("all") == 0) {
     1583        itr = _contour3Ds.begin();
     1584        doAll = true;
     1585    } else {
     1586        itr = _contour3Ds.find(id);
     1587    }
     1588    if (itr == _contour3Ds.end()) {
     1589        ERROR("Contour3D not found: %s", id.c_str());
    10041590        return;
    10051591    }
     
    10071593    do {
    10081594        itr->second->setEdgeWidth(edgeWidth);
    1009     } while (doAll && ++itr != _pseudoColors.end());
    1010 
    1011     _needsRedraw = true;
    1012 }
    1013 
    1014 /**
    1015  * \brief Turn mesh lighting on/off for the specified DataSet
    1016  */
    1017 void Renderer::setPseudoColorLighting(const DataSetId& id, bool state)
    1018 {
    1019     PseudoColorHashmap::iterator itr;
    1020 
    1021     bool doAll = false;
    1022 
    1023     if (id.compare("all") == 0) {
    1024         itr = _pseudoColors.begin();
    1025         doAll = true;
    1026     } else {
    1027         itr = _pseudoColors.find(id);
    1028     }
    1029 
    1030     if (itr == _pseudoColors.end()) {
    1031         ERROR("PseudoColor not found: %s", id.c_str());
     1595    } while (doAll && ++itr != _contour3Ds.end());
     1596
     1597    _needsRedraw = true;
     1598}
     1599
     1600/**
     1601 * \brief Set wireframe rendering for the specified DataSet
     1602 */
     1603void Renderer::setContour3DWireframe(const DataSetId& id, bool state)
     1604{
     1605    Contour3DHashmap::iterator itr;
     1606
     1607    bool doAll = false;
     1608
     1609    if (id.compare("all") == 0) {
     1610        itr = _contour3Ds.begin();
     1611        doAll = true;
     1612    } else {
     1613        itr = _contour3Ds.find(id);
     1614    }
     1615    if (itr == _contour3Ds.end()) {
     1616        ERROR("Contour3D not found: %s", id.c_str());
     1617        return;
     1618    }
     1619
     1620    do {
     1621        itr->second->setWireframe(state);
     1622    } while (doAll && ++itr != _contour3Ds.end());
     1623
     1624    _needsRedraw = true;
     1625}
     1626
     1627/**
     1628 * \brief Turn contour lighting on/off for the specified DataSet
     1629 */
     1630void Renderer::setContour3DLighting(const DataSetId& id, bool state)
     1631{
     1632    Contour3DHashmap::iterator itr;
     1633
     1634    bool doAll = false;
     1635
     1636    if (id.compare("all") == 0) {
     1637        itr = _contour3Ds.begin();
     1638        doAll = true;
     1639    } else {
     1640        itr = _contour3Ds.find(id);
     1641    }
     1642    if (itr == _contour3Ds.end()) {
     1643        ERROR("Contour3D not found: %s", id.c_str());
    10321644        return;
    10331645    }
     
    10351647    do {
    10361648        itr->second->setLighting(state);
    1037     } while (doAll && ++itr != _pseudoColors.end());
    1038 
    1039     _needsRedraw = true;
    1040 }
    1041 
    1042 /**
    1043  * \brief Create a new Contour2D and associate it with the named DataSet
    1044  */
    1045 void Renderer::addContour2D(const DataSetId& id)
     1649    } while (doAll && ++itr != _contour3Ds.end());
     1650    _needsRedraw = true;
     1651}
     1652
     1653/**
     1654 * \brief Create a new Glyphs and associate it with the named DataSet
     1655 */
     1656void Renderer::addGlyphs(const DataSetId& id)
    10461657{
    10471658    DataSetHashmap::iterator itr;
     
    10631674        const DataSetId& dsID = ds->getName();
    10641675
    1065         if (getContour2D(dsID)) {
    1066             WARN("Replacing existing contour2d %s", dsID.c_str());
    1067             deleteContour2D(dsID);
    1068         }
    1069 
    1070         Contour2D *contour = new Contour2D();
    1071         _contours[dsID] = contour;
    1072 
    1073         contour->setDataSet(ds);
    1074 
    1075         _renderer->AddActor(contour->getActor());
     1676        if (getGlyphs(dsID)) {
     1677            WARN("Replacing existing Glyphs %s", dsID.c_str());
     1678            deleteGlyphs(dsID);
     1679        }
     1680
     1681        Glyphs *glyphs = new Glyphs();
     1682        _glyphs[dsID] = glyphs;
     1683
     1684        glyphs->setDataSet(ds);
     1685
     1686        // Use the default color map
     1687        vtkSmartPointer<vtkLookupTable> lut = vtkSmartPointer<vtkLookupTable>::New();
     1688        ColorMap *cmap = getColorMap("default");
     1689        lut->DeepCopy(cmap->getLookupTable());
     1690        if (_useCumulativeRange) {
     1691            lut->SetRange(_cumulativeDataRange);
     1692        } else {
     1693            double range[2];
     1694            ds->getDataRange(range);
     1695            lut->SetRange(range);
     1696        }
     1697
     1698        glyphs->setLookupTable(lut);
     1699
     1700        _renderer->AddViewProp(glyphs->getProp());
    10761701    } while (doAll && ++itr != _dataSets.end());
    10771702
     1703    if (_cameraMode == IMAGE)
     1704        setCameraMode(PERSPECTIVE);
    10781705    initCamera();
    1079     _needsRedraw = true;
    1080 }
    1081 
    1082 /**
    1083  * \brief Get the Contour2D associated with a named DataSet
    1084  */
    1085 Contour2D *Renderer::getContour2D(const DataSetId& id)
    1086 {
    1087     Contour2DHashmap::iterator itr = _contours.find(id);
    1088 
    1089     if (itr == _contours.end()) {
    1090         TRACE("Contour2D not found: %s", id.c_str());
     1706
     1707    _needsRedraw = true;
     1708}
     1709
     1710/**
     1711 * \brief Get the Glyphs associated with a named DataSet
     1712 */
     1713Glyphs *Renderer::getGlyphs(const DataSetId& id)
     1714{
     1715    GlyphsHashmap::iterator itr = _glyphs.find(id);
     1716
     1717    if (itr == _glyphs.end()) {
     1718        TRACE("Glyphs not found: %s", id.c_str());
    10911719        return NULL;
    10921720    } else
     
    10951723
    10961724/**
     1725 * \brief Associate an existing named color map with a Glyphs for the given DataSet
     1726 */
     1727void Renderer::setGlyphsColorMap(const DataSetId& id, const ColorMapId& colorMapId)
     1728{
     1729    GlyphsHashmap::iterator itr;
     1730
     1731    bool doAll = false;
     1732
     1733    if (id.compare("all") == 0) {
     1734        itr = _glyphs.begin();
     1735        doAll = true;
     1736    } else {
     1737        itr = _glyphs.find(id);
     1738    }
     1739
     1740    if (itr == _glyphs.end()) {
     1741        ERROR("Glyphs not found: %s", id.c_str());
     1742        return;
     1743    }
     1744
     1745    ColorMap *cmap = getColorMap(colorMapId);
     1746    if (cmap == NULL) {
     1747        ERROR("Unknown colormap: %s", colorMapId.c_str());
     1748        return;
     1749    }
     1750
     1751    do {
     1752        TRACE("Set Glyphs color map: %s for dataset %s", colorMapId.c_str(),
     1753              itr->second->getDataSet()->getName().c_str());
     1754
     1755        // Make a copy of the generic colormap lookup table, so
     1756        // data range can be set in the copy table to match the
     1757        // dataset being plotted
     1758        vtkSmartPointer<vtkLookupTable> lut = vtkSmartPointer<vtkLookupTable>::New();
     1759        lut->DeepCopy(cmap->getLookupTable());
     1760
     1761        if (_useCumulativeRange) {
     1762            lut->SetRange(_cumulativeDataRange);
     1763        } else {
     1764            if (itr->second->getDataSet() != NULL) {
     1765                double range[2];
     1766                itr->second->getDataSet()->getDataRange(range);
     1767                lut->SetRange(range);
     1768            }
     1769        }
     1770
     1771        itr->second->setLookupTable(lut);
     1772    } while (doAll && ++itr != _glyphs.end());
     1773
     1774    _needsRedraw = true;
     1775}
     1776
     1777/**
     1778 * \brief Set the shape of Glyphs for the given DataSet
     1779 */
     1780void Renderer::setGlyphsShape(const DataSetId& id, Glyphs::GlyphShape shape)
     1781{
     1782    GlyphsHashmap::iterator itr;
     1783
     1784    bool doAll = false;
     1785
     1786    if (id.compare("all") == 0) {
     1787        itr = _glyphs.begin();
     1788        doAll = true;
     1789    } else {
     1790        itr = _glyphs.find(id);
     1791    }
     1792    if (itr == _glyphs.end()) {
     1793        ERROR("Glyphs not found: %s", id.c_str());
     1794        return;
     1795    }
     1796
     1797    do {
     1798        itr->second->setGlyphShape(shape);
     1799    } while (doAll && ++itr != _glyphs.end());
     1800
     1801    _renderer->ResetCameraClippingRange();
     1802    _needsRedraw = true;
     1803}
     1804
     1805/**
     1806 * \brief Set the glyph scaling factor for the given DataSet
     1807 */
     1808void Renderer::setGlyphsScaleFactor(const DataSetId& id, double scale)
     1809{
     1810    GlyphsHashmap::iterator itr;
     1811
     1812    bool doAll = false;
     1813
     1814    if (id.compare("all") == 0) {
     1815        itr = _glyphs.begin();
     1816        doAll = true;
     1817    } else {
     1818        itr = _glyphs.find(id);
     1819    }
     1820    if (itr == _glyphs.end()) {
     1821        ERROR("Glyphs not found: %s", id.c_str());
     1822        return;
     1823    }
     1824
     1825    do {
     1826        itr->second->setScaleFactor(scale);
     1827    } while (doAll && ++itr != _glyphs.end());
     1828
     1829    _renderer->ResetCameraClippingRange();
     1830    _needsRedraw = true;
     1831}
     1832
     1833/**
     1834 * \brief Set opacity of Glyphs for the given DataSet
     1835 */
     1836void Renderer::setGlyphsOpacity(const DataSetId& id, double opacity)
     1837{
     1838    GlyphsHashmap::iterator itr;
     1839
     1840    bool doAll = false;
     1841
     1842    if (id.compare("all") == 0) {
     1843        itr = _glyphs.begin();
     1844        doAll = true;
     1845    } else {
     1846        itr = _glyphs.find(id);
     1847    }
     1848    if (itr == _glyphs.end()) {
     1849        ERROR("Glyphs not found: %s", id.c_str());
     1850        return;
     1851    }
     1852
     1853    do {
     1854        itr->second->setOpacity(opacity);
     1855    } while (doAll && ++itr != _glyphs.end());
     1856
     1857    _needsRedraw = true;
     1858}
     1859
     1860/**
     1861 * \brief Turn on/off rendering Glyphs for the given DataSet
     1862 */
     1863void Renderer::setGlyphsVisibility(const DataSetId& id, bool state)
     1864{
     1865    GlyphsHashmap::iterator itr;
     1866
     1867    bool doAll = false;
     1868
     1869    if (id.compare("all") == 0) {
     1870        itr = _glyphs.begin();
     1871        doAll = true;
     1872    } else {
     1873        itr = _glyphs.find(id);
     1874    }
     1875    if (itr == _glyphs.end()) {
     1876        ERROR("Glyphs not found: %s", id.c_str());
     1877        return;
     1878    }
     1879
     1880    do {
     1881        itr->second->setVisibility(state);
     1882    } while (doAll && ++itr != _glyphs.end());
     1883
     1884    _needsRedraw = true;
     1885}
     1886
     1887/**
     1888 * \brief Turn Glyphs lighting on/off for the specified DataSet
     1889 */
     1890void Renderer::setGlyphsLighting(const DataSetId& id, bool state)
     1891{
     1892    GlyphsHashmap::iterator itr;
     1893
     1894    bool doAll = false;
     1895
     1896    if (id.compare("all") == 0) {
     1897        itr = _glyphs.begin();
     1898        doAll = true;
     1899    } else {
     1900        itr = _glyphs.find(id);
     1901    }
     1902    if (itr == _glyphs.end()) {
     1903        ERROR("Glyphs not found: %s", id.c_str());
     1904        return;
     1905    }
     1906
     1907    do {
     1908        itr->second->setLighting(state);
     1909    } while (doAll && ++itr != _glyphs.end());
     1910    _needsRedraw = true;
     1911}
     1912
     1913/**
     1914 * \brief Create a new HeightMap and associate it with the named DataSet
     1915 */
     1916void Renderer::addHeightMap(const DataSetId& id)
     1917{
     1918    DataSetHashmap::iterator itr;
     1919
     1920    bool doAll = false;
     1921
     1922    if (id.compare("all") == 0) {
     1923        itr = _dataSets.begin();
     1924    } else {
     1925        itr = _dataSets.find(id);
     1926    }
     1927    if (itr == _dataSets.end()) {
     1928        ERROR("Unknown dataset %s", id.c_str());
     1929        return;
     1930    }
     1931
     1932    do {
     1933        DataSet *ds = itr->second;
     1934        const DataSetId& dsID = ds->getName();
     1935
     1936        if (getHeightMap(dsID)) {
     1937            WARN("Replacing existing HeightMap %s", dsID.c_str());
     1938            deleteHeightMap(dsID);
     1939        }
     1940
     1941        HeightMap *hmap = new HeightMap();
     1942        _heightMaps[dsID] = hmap;
     1943
     1944        hmap->setDataSet(ds);
     1945
     1946        // Use the default color map
     1947        vtkSmartPointer<vtkLookupTable> lut = vtkSmartPointer<vtkLookupTable>::New();
     1948        ColorMap *cmap = getColorMap("default");
     1949        lut->DeepCopy(cmap->getLookupTable());
     1950        if (_useCumulativeRange) {
     1951            lut->SetRange(_cumulativeDataRange);
     1952        } else {
     1953            double range[2];
     1954            ds->getDataRange(range);
     1955            lut->SetRange(range);
     1956        }
     1957
     1958        hmap->setLookupTable(lut);
     1959
     1960        _renderer->AddViewProp(hmap->getProp());
     1961    } while (doAll && ++itr != _dataSets.end());
     1962
     1963    if (_cameraMode == IMAGE)
     1964        setCameraMode(PERSPECTIVE);
     1965    initCamera();
     1966
     1967    _needsRedraw = true;
     1968}
     1969
     1970/**
     1971 * \brief Get the HeightMap associated with a named DataSet
     1972 */
     1973HeightMap *Renderer::getHeightMap(const DataSetId& id)
     1974{
     1975    HeightMapHashmap::iterator itr = _heightMaps.find(id);
     1976
     1977    if (itr == _heightMaps.end()) {
     1978        TRACE("HeightMap not found: %s", id.c_str());
     1979        return NULL;
     1980    } else
     1981        return itr->second;
     1982}
     1983
     1984/**
     1985 * \brief Set the volume slice used for mapping volumetric data
     1986 */
     1987void Renderer::setHeightMapVolumeSlice(const DataSetId& id, HeightMap::Axis axis, double ratio)
     1988{
     1989    HeightMapHashmap::iterator itr;
     1990
     1991    bool doAll = false;
     1992
     1993    if (id.compare("all") == 0) {
     1994        itr = _heightMaps.begin();
     1995        doAll = true;
     1996    } else {
     1997        itr = _heightMaps.find(id);
     1998    }
     1999
     2000    if (itr == _heightMaps.end()) {
     2001        ERROR("HeightMap not found: %s", id.c_str());
     2002        return;
     2003    }
     2004
     2005    do {
     2006        itr->second->selectVolumeSlice(axis, ratio);
     2007     } while (doAll && ++itr != _heightMaps.end());
     2008
     2009    initCamera();
     2010    _needsRedraw = true;
     2011}
     2012
     2013/**
     2014 * \brief Set amount to scale scalar values when creating elevations
     2015 * in the height map
     2016 */
     2017void Renderer::setHeightMapHeightScale(const DataSetId& id, double scale)
     2018{
     2019    HeightMapHashmap::iterator itr;
     2020
     2021    bool doAll = false;
     2022
     2023    if (id.compare("all") == 0) {
     2024        itr = _heightMaps.begin();
     2025        doAll = true;
     2026    } else {
     2027        itr = _heightMaps.find(id);
     2028    }
     2029
     2030    if (itr == _heightMaps.end()) {
     2031        ERROR("HeightMap not found: %s", id.c_str());
     2032        return;
     2033    }
     2034
     2035    do {
     2036        itr->second->setHeightScale(scale);
     2037     } while (doAll && ++itr != _heightMaps.end());
     2038
     2039    initCamera();
     2040    _needsRedraw = true;
     2041}
     2042
     2043/**
     2044 * \brief Associate an existing named color map with a HeightMap for the given DataSet
     2045 */
     2046void Renderer::setHeightMapColorMap(const DataSetId& id, const ColorMapId& colorMapId)
     2047{
     2048    HeightMapHashmap::iterator itr;
     2049
     2050    bool doAll = false;
     2051
     2052    if (id.compare("all") == 0) {
     2053        itr = _heightMaps.begin();
     2054        doAll = true;
     2055    } else {
     2056        itr = _heightMaps.find(id);
     2057    }
     2058
     2059    if (itr == _heightMaps.end()) {
     2060        ERROR("HeightMap not found: %s", id.c_str());
     2061        return;
     2062    }
     2063
     2064    ColorMap *cmap = getColorMap(colorMapId);
     2065    if (cmap == NULL) {
     2066        ERROR("Unknown colormap: %s", colorMapId.c_str());
     2067        return;
     2068    }
     2069
     2070    do {
     2071        TRACE("Set HeightMap color map: %s for dataset %s", colorMapId.c_str(),
     2072              itr->second->getDataSet()->getName().c_str());
     2073
     2074        // Make a copy of the generic colormap lookup table, so
     2075        // data range can be set in the copy table to match the
     2076        // dataset being plotted
     2077        vtkSmartPointer<vtkLookupTable> lut = vtkSmartPointer<vtkLookupTable>::New();
     2078        lut->DeepCopy(cmap->getLookupTable());
     2079
     2080        if (_useCumulativeRange) {
     2081            lut->SetRange(_cumulativeDataRange);
     2082        } else {
     2083            if (itr->second->getDataSet() != NULL) {
     2084                double range[2];
     2085                itr->second->getDataSet()->getDataRange(range);
     2086                lut->SetRange(range);
     2087            }
     2088        }
     2089
     2090        itr->second->setLookupTable(lut);
     2091    } while (doAll && ++itr != _heightMaps.end());
     2092
     2093    _needsRedraw = true;
     2094}
     2095
     2096/**
    10972097 * \brief Set the number of equally spaced contour isolines for the given DataSet
    10982098 */
    1099 void Renderer::setContours(const DataSetId& id, int numContours)
    1100 {
    1101     Contour2DHashmap::iterator itr;
    1102 
    1103     bool doAll = false;
    1104 
    1105     if (id.compare("all") == 0) {
    1106         itr = _contours.begin();
    1107         doAll = true;
    1108     } else {
    1109         itr = _contours.find(id);
    1110     }
    1111     if (itr == _contours.end()) {
    1112         ERROR("Contour2D not found: %s", id.c_str());
     2099void Renderer::setHeightMapContours(const DataSetId& id, int numContours)
     2100{
     2101    HeightMapHashmap::iterator itr;
     2102
     2103    bool doAll = false;
     2104
     2105    if (id.compare("all") == 0) {
     2106        itr = _heightMaps.begin();
     2107        doAll = true;
     2108    } else {
     2109        itr = _heightMaps.find(id);
     2110    }
     2111    if (itr == _heightMaps.end()) {
     2112        ERROR("HeightMap not found: %s", id.c_str());
    11132113        return;
    11142114    }
     
    11202120            itr->second->setContours(numContours);
    11212121        }
    1122     } while (doAll && ++itr != _contours.end());
    1123 
    1124     _needsRedraw = true;
    1125 }
    1126 
    1127 /**
    1128  * \brief Set a list of isovalues for the given DataSet
    1129  */
    1130 void Renderer::setContourList(const DataSetId& id, const std::vector<double>& contours)
    1131 {
    1132     Contour2DHashmap::iterator itr;
    1133 
    1134     bool doAll = false;
    1135 
    1136     if (id.compare("all") == 0) {
    1137         itr = _contours.begin();
    1138         doAll = true;
    1139     } else {
    1140         itr = _contours.find(id);
    1141     }
    1142     if (itr == _contours.end()) {
    1143         ERROR("Contour2D not found: %s", id.c_str());
     2122    } while (doAll && ++itr != _heightMaps.end());
     2123
     2124    _needsRedraw = true;
     2125}
     2126
     2127/**
     2128 * \brief Set a list of height map contour isovalues for the given DataSet
     2129 */
     2130void Renderer::setHeightMapContourList(const DataSetId& id, const std::vector<double>& contours)
     2131{
     2132    HeightMapHashmap::iterator itr;
     2133
     2134    bool doAll = false;
     2135
     2136    if (id.compare("all") == 0) {
     2137        itr = _heightMaps.begin();
     2138        doAll = true;
     2139    } else {
     2140        itr = _heightMaps.find(id);
     2141    }
     2142    if (itr == _heightMaps.end()) {
     2143        ERROR("HeightMap not found: %s", id.c_str());
    11442144        return;
    11452145    }
     
    11472147    do {
    11482148        itr->second->setContourList(contours);
    1149     } while (doAll && ++itr != _contours.end());
     2149    } while (doAll && ++itr != _heightMaps.end());
    11502150
    11512151     _needsRedraw = true;
     
    11532153
    11542154/**
    1155  * \brief Set opacity of contour lines for the given DataSet
    1156  */
    1157 void Renderer::setContourOpacity(const DataSetId& id, double opacity)
    1158 {
    1159     Contour2DHashmap::iterator itr;
    1160 
    1161     bool doAll = false;
    1162 
    1163     if (id.compare("all") == 0) {
    1164         itr = _contours.begin();
    1165         doAll = true;
    1166     } else {
    1167         itr = _contours.find(id);
    1168     }
    1169     if (itr == _contours.end()) {
    1170         ERROR("Contour2D not found: %s", id.c_str());
     2155 * \brief Set opacity of height map for the given DataSet
     2156 */
     2157void Renderer::setHeightMapOpacity(const DataSetId& id, double opacity)
     2158{
     2159    HeightMapHashmap::iterator itr;
     2160
     2161    bool doAll = false;
     2162
     2163    if (id.compare("all") == 0) {
     2164        itr = _heightMaps.begin();
     2165        doAll = true;
     2166    } else {
     2167        itr = _heightMaps.find(id);
     2168    }
     2169    if (itr == _heightMaps.end()) {
     2170        ERROR("HeightMap not found: %s", id.c_str());
    11712171        return;
    11722172    }
     
    11742174    do {
    11752175        itr->second->setOpacity(opacity);
    1176     } while (doAll && ++itr != _contours.end());
    1177 
    1178     _needsRedraw = true;
    1179 }
    1180 
    1181 /**
    1182  * \brief Turn on/off rendering contour lines for the given DataSet
    1183  */
    1184 void Renderer::setContourVisibility(const DataSetId& id, bool state)
    1185 {
    1186     Contour2DHashmap::iterator itr;
    1187 
    1188     bool doAll = false;
    1189 
    1190     if (id.compare("all") == 0) {
    1191         itr = _contours.begin();
    1192         doAll = true;
    1193     } else {
    1194         itr = _contours.find(id);
    1195     }
    1196     if (itr == _contours.end()) {
    1197         ERROR("Contour2D not found: %s", id.c_str());
     2176    } while (doAll && ++itr != _heightMaps.end());
     2177
     2178    _needsRedraw = true;
     2179}
     2180
     2181/**
     2182 * \brief Turn on/off rendering height map for the given DataSet
     2183 */
     2184void Renderer::setHeightMapVisibility(const DataSetId& id, bool state)
     2185{
     2186    HeightMapHashmap::iterator itr;
     2187
     2188    bool doAll = false;
     2189
     2190    if (id.compare("all") == 0) {
     2191        itr = _heightMaps.begin();
     2192        doAll = true;
     2193    } else {
     2194        itr = _heightMaps.find(id);
     2195    }
     2196    if (itr == _heightMaps.end()) {
     2197        ERROR("HeightMap not found: %s", id.c_str());
    11982198        return;
    11992199    }
     
    12012201    do {
    12022202        itr->second->setVisibility(state);
    1203     } while (doAll && ++itr != _contours.end());
    1204 
    1205     _needsRedraw = true;
    1206 }
    1207 
    1208 /**
    1209  * \brief Set the RGB isoline color for the specified DataSet
    1210  */
    1211 void Renderer::setContourEdgeColor(const DataSetId& id, float color[3])
    1212 {
    1213     Contour2DHashmap::iterator itr;
    1214 
    1215     bool doAll = false;
    1216 
    1217     if (id.compare("all") == 0) {
    1218         itr = _contours.begin();
    1219         doAll = true;
    1220     } else {
    1221         itr = _contours.find(id);
    1222     }
    1223     if (itr == _contours.end()) {
    1224         ERROR("Contour2D not found: %s", id.c_str());
     2203    } while (doAll && ++itr != _heightMaps.end());
     2204
     2205    _needsRedraw = true;
     2206}
     2207
     2208/**
     2209 * \brief Turn on/off rendering height map mesh edges for the given DataSet
     2210 */
     2211void Renderer::setHeightMapEdgeVisibility(const DataSetId& id, bool state)
     2212{
     2213    HeightMapHashmap::iterator itr;
     2214
     2215    bool doAll = false;
     2216
     2217    if (id.compare("all") == 0) {
     2218        itr = _heightMaps.begin();
     2219        doAll = true;
     2220    } else {
     2221        itr = _heightMaps.find(id);
     2222    }
     2223    if (itr == _heightMaps.end()) {
     2224        ERROR("HeightMap not found: %s", id.c_str());
     2225        return;
     2226    }
     2227
     2228    do {
     2229        itr->second->setEdgeVisibility(state);
     2230    } while (doAll && ++itr != _heightMaps.end());
     2231
     2232    _needsRedraw = true;
     2233}
     2234
     2235/**
     2236 * \brief Set the RGB height map mesh edge color for the specified DataSet
     2237 */
     2238void Renderer::setHeightMapEdgeColor(const DataSetId& id, float color[3])
     2239{
     2240    HeightMapHashmap::iterator itr;
     2241
     2242    bool doAll = false;
     2243
     2244    if (id.compare("all") == 0) {
     2245        itr = _heightMaps.begin();
     2246        doAll = true;
     2247    } else {
     2248        itr = _heightMaps.find(id);
     2249    }
     2250    if (itr == _heightMaps.end()) {
     2251        ERROR("HeightMap not found: %s", id.c_str());
    12252252        return;
    12262253    }
     
    12282255    do {
    12292256        itr->second->setEdgeColor(color);
    1230     } while (doAll && ++itr != _contours.end());
    1231 
    1232     _needsRedraw = true;
    1233 }
    1234 
    1235 /**
    1236  * \brief Set the isoline width for the specified DataSet (may be a no-op)
     2257    } while (doAll && ++itr != _heightMaps.end());
     2258
     2259    _needsRedraw = true;
     2260}
     2261
     2262/**
     2263 * \brief Set the height map mesh edge width for the specified DataSet (may be a no-op)
    12372264 *
    12382265 * If the OpenGL implementation/hardware does not support wide lines,
    12392266 * this function may not have an effect.
    12402267 */
    1241 void Renderer::setContourEdgeWidth(const DataSetId& id, float edgeWidth)
    1242 {
    1243     Contour2DHashmap::iterator itr;
    1244 
    1245     bool doAll = false;
    1246 
    1247     if (id.compare("all") == 0) {
    1248         itr = _contours.begin();
    1249         doAll = true;
    1250     } else {
    1251         itr = _contours.find(id);
    1252     }
    1253     if (itr == _contours.end()) {
    1254         ERROR("Contour2D not found: %s", id.c_str());
     2268void Renderer::setHeightMapEdgeWidth(const DataSetId& id, float edgeWidth)
     2269{
     2270    HeightMapHashmap::iterator itr;
     2271
     2272    bool doAll = false;
     2273
     2274    if (id.compare("all") == 0) {
     2275        itr = _heightMaps.begin();
     2276        doAll = true;
     2277    } else {
     2278        itr = _heightMaps.find(id);
     2279    }
     2280    if (itr == _heightMaps.end()) {
     2281        ERROR("HeightMap not found: %s", id.c_str());
    12552282        return;
    12562283    }
     
    12582285    do {
    12592286        itr->second->setEdgeWidth(edgeWidth);
    1260     } while (doAll && ++itr != _contours.end());
    1261 
    1262     _needsRedraw = true;
    1263 }
    1264 
    1265 /**
    1266  * \brief Turn contour lighting on/off for the specified DataSet
    1267  */
    1268 void Renderer::setContourLighting(const DataSetId& id, bool state)
    1269 {
    1270     Contour2DHashmap::iterator itr;
    1271 
    1272     bool doAll = false;
    1273 
    1274     if (id.compare("all") == 0) {
    1275         itr = _contours.begin();
    1276         doAll = true;
    1277     } else {
    1278         itr = _contours.find(id);
    1279     }
    1280     if (itr == _contours.end()) {
    1281         ERROR("Contour2D not found: %s", id.c_str());
     2287    } while (doAll && ++itr != _heightMaps.end());
     2288
     2289    _needsRedraw = true;
     2290}
     2291
     2292/**
     2293 * \brief Turn on/off rendering height map contour lines for the given DataSet
     2294 */
     2295void Renderer::setHeightMapContourVisibility(const DataSetId& id, bool state)
     2296{
     2297    HeightMapHashmap::iterator itr;
     2298
     2299    bool doAll = false;
     2300
     2301    if (id.compare("all") == 0) {
     2302        itr = _heightMaps.begin();
     2303        doAll = true;
     2304    } else {
     2305        itr = _heightMaps.find(id);
     2306    }
     2307    if (itr == _heightMaps.end()) {
     2308        ERROR("HeightMap not found: %s", id.c_str());
     2309        return;
     2310    }
     2311
     2312    do {
     2313        itr->second->setContourVisibility(state);
     2314    } while (doAll && ++itr != _heightMaps.end());
     2315
     2316    _needsRedraw = true;
     2317}
     2318
     2319/**
     2320 * \brief Set the RGB height map isoline color for the specified DataSet
     2321 */
     2322void Renderer::setHeightMapContourEdgeColor(const DataSetId& id, float color[3])
     2323{
     2324    HeightMapHashmap::iterator itr;
     2325
     2326    bool doAll = false;
     2327
     2328    if (id.compare("all") == 0) {
     2329        itr = _heightMaps.begin();
     2330        doAll = true;
     2331    } else {
     2332        itr = _heightMaps.find(id);
     2333    }
     2334    if (itr == _heightMaps.end()) {
     2335        ERROR("HeightMap not found: %s", id.c_str());
     2336        return;
     2337    }
     2338
     2339    do {
     2340        itr->second->setContourEdgeColor(color);
     2341    } while (doAll && ++itr != _heightMaps.end());
     2342
     2343    _needsRedraw = true;
     2344}
     2345
     2346/**
     2347 * \brief Set the height map isoline width for the specified DataSet (may be a no-op)
     2348 *
     2349 * If the OpenGL implementation/hardware does not support wide lines,
     2350 * this function may not have an effect.
     2351 */
     2352void Renderer::setHeightMapContourEdgeWidth(const DataSetId& id, float edgeWidth)
     2353{
     2354    HeightMapHashmap::iterator itr;
     2355
     2356    bool doAll = false;
     2357
     2358    if (id.compare("all") == 0) {
     2359        itr = _heightMaps.begin();
     2360        doAll = true;
     2361    } else {
     2362        itr = _heightMaps.find(id);
     2363    }
     2364    if (itr == _heightMaps.end()) {
     2365        ERROR("HeightMap not found: %s", id.c_str());
     2366        return;
     2367    }
     2368
     2369    do {
     2370        itr->second->setContourEdgeWidth(edgeWidth);
     2371    } while (doAll && ++itr != _heightMaps.end());
     2372
     2373    _needsRedraw = true;
     2374}
     2375
     2376/**
     2377 * \brief Turn height map lighting on/off for the specified DataSet
     2378 */
     2379void Renderer::setHeightMapLighting(const DataSetId& id, bool state)
     2380{
     2381    HeightMapHashmap::iterator itr;
     2382
     2383    bool doAll = false;
     2384
     2385    if (id.compare("all") == 0) {
     2386        itr = _heightMaps.begin();
     2387        doAll = true;
     2388    } else {
     2389        itr = _heightMaps.find(id);
     2390    }
     2391    if (itr == _heightMaps.end()) {
     2392        ERROR("HeightMap not found: %s", id.c_str());
    12822393        return;
    12832394    }
     
    12852396    do {
    12862397        itr->second->setLighting(state);
    1287     } while (doAll && ++itr != _contours.end());
     2398    } while (doAll && ++itr != _heightMaps.end());
    12882399    _needsRedraw = true;
    12892400}
     
    13222433        polyData->setDataSet(ds);
    13232434
    1324         _renderer->AddActor(polyData->getActor());
     2435        _renderer->AddViewProp(polyData->getProp());
    13252436    } while (doAll && ++itr != _dataSets.end());
    13262437
     
    13512462{
    13522463    PolyDataHashmap::iterator itr;
    1353    
     2464
    13542465    bool doAll = false;
    13552466
     
    13782489{
    13792490    PolyDataHashmap::iterator itr;
    1380    
     2491
    13812492    bool doAll = false;
    13822493
     
    14052516{
    14062517    PolyDataHashmap::iterator itr;
    1407    
     2518
    14082519    bool doAll = false;
    14092520
     
    14312542{
    14322543    PolyDataHashmap::iterator itr;
    1433    
     2544
    14342545    bool doAll = false;
    14352546
     
    14582569{
    14592570    PolyDataHashmap::iterator itr;
    1460    
     2571
    14612572    bool doAll = false;
    14622573
     
    14882599{
    14892600    PolyDataHashmap::iterator itr;
    1490    
     2601
    14912602    bool doAll = false;
    14922603
     
    15152626{
    15162627    PolyDataHashmap::iterator itr;
    1517    
     2628
    15182629    bool doAll = false;
    15192630
     
    15422653{
    15432654    PolyDataHashmap::iterator itr;
    1544    
     2655
    15452656    bool doAll = false;
    15462657
     
    15642675
    15652676/**
     2677 * \brief Create a new PseudoColor rendering for the specified DataSet
     2678 */
     2679void Renderer::addPseudoColor(const DataSetId& id)
     2680{
     2681    DataSetHashmap::iterator itr;
     2682
     2683    bool doAll = false;
     2684
     2685    if (id.compare("all") == 0) {
     2686        itr = _dataSets.begin();
     2687    } else {
     2688        itr = _dataSets.find(id);
     2689    }
     2690    if (itr == _dataSets.end()) {
     2691        ERROR("Unknown dataset %s", id.c_str());
     2692        return;
     2693    }
     2694
     2695    do {
     2696        DataSet *ds = itr->second;
     2697        const DataSetId& dsID = ds->getName();
     2698
     2699        if (getPseudoColor(dsID)) {
     2700            WARN("Replacing existing pseudocolor %s", dsID.c_str());
     2701            deletePseudoColor(dsID);
     2702        }
     2703        PseudoColor *pc = new PseudoColor();
     2704        _pseudoColors[dsID] = pc;
     2705
     2706        pc->setDataSet(ds);
     2707
     2708        // Use the default color map
     2709        vtkSmartPointer<vtkLookupTable> lut = vtkSmartPointer<vtkLookupTable>::New();
     2710        ColorMap *cmap = getColorMap("default");
     2711        lut->DeepCopy(cmap->getLookupTable());
     2712        if (_useCumulativeRange) {
     2713            lut->SetRange(_cumulativeDataRange);
     2714        } else {
     2715            double range[2];
     2716            ds->getDataRange(range);
     2717            lut->SetRange(range);
     2718        }
     2719
     2720        pc->setLookupTable(lut);
     2721
     2722        _renderer->AddViewProp(pc->getProp());
     2723    } while (doAll && ++itr != _dataSets.end());
     2724
     2725    initCamera();
     2726    _needsRedraw = true;
     2727}
     2728
     2729/**
     2730 * \brief Get the PseudoColor associated with the specified DataSet
     2731 */
     2732PseudoColor *Renderer::getPseudoColor(const DataSetId& id)
     2733{
     2734    PseudoColorHashmap::iterator itr = _pseudoColors.find(id);
     2735
     2736    if (itr == _pseudoColors.end()) {
     2737        TRACE("PseudoColor not found: %s", id.c_str());
     2738        return NULL;
     2739    } else
     2740        return itr->second;
     2741}
     2742
     2743/**
     2744 * \brief Associate an existing named color map with a PseudoColor for the given DataSet
     2745 */
     2746void Renderer::setPseudoColorColorMap(const DataSetId& id, const ColorMapId& colorMapId)
     2747{
     2748    PseudoColorHashmap::iterator itr;
     2749
     2750    bool doAll = false;
     2751
     2752    if (id.compare("all") == 0) {
     2753        itr = _pseudoColors.begin();
     2754        doAll = true;
     2755    } else {
     2756        itr = _pseudoColors.find(id);
     2757    }
     2758
     2759    if (itr == _pseudoColors.end()) {
     2760        ERROR("PseudoColor not found: %s", id.c_str());
     2761        return;
     2762    }
     2763
     2764    ColorMap *cmap = getColorMap(colorMapId);
     2765    if (cmap == NULL) {
     2766        ERROR("Unknown colormap: %s", colorMapId.c_str());
     2767        return;
     2768    }
     2769
     2770    do {
     2771        TRACE("Set PseudoColor color map: %s for dataset %s", colorMapId.c_str(),
     2772              itr->second->getDataSet()->getName().c_str());
     2773
     2774        // Make a copy of the generic colormap lookup table, so
     2775        // data range can be set in the copy table to match the
     2776        // dataset being plotted
     2777        vtkSmartPointer<vtkLookupTable> lut = vtkSmartPointer<vtkLookupTable>::New();
     2778        lut->DeepCopy(cmap->getLookupTable());
     2779
     2780        if (_useCumulativeRange) {
     2781            lut->SetRange(_cumulativeDataRange);
     2782        } else {
     2783            if (itr->second->getDataSet() != NULL) {
     2784                double range[2];
     2785                itr->second->getDataSet()->getDataRange(range);
     2786                lut->SetRange(range);
     2787            }
     2788        }
     2789
     2790        itr->second->setLookupTable(lut);
     2791    } while (doAll && ++itr != _pseudoColors.end());
     2792
     2793    _needsRedraw = true;
     2794}
     2795
     2796/**
     2797 * \brief Set opacity of the PseudoColor for the given DataSet
     2798 */
     2799void Renderer::setPseudoColorOpacity(const DataSetId& id, double opacity)
     2800{
     2801    PseudoColorHashmap::iterator itr;
     2802
     2803    bool doAll = false;
     2804
     2805    if (id.compare("all") == 0) {
     2806        itr = _pseudoColors.begin();
     2807        doAll = true;
     2808    } else {
     2809        itr = _pseudoColors.find(id);
     2810    }
     2811
     2812    if (itr == _pseudoColors.end()) {
     2813        ERROR("PseudoColor not found: %s", id.c_str());
     2814        return;
     2815    }
     2816
     2817    do {
     2818        itr->second->setOpacity(opacity);
     2819    } while (doAll && ++itr != _pseudoColors.end());
     2820
     2821    _needsRedraw = true;
     2822}
     2823
     2824/**
     2825 * \brief Turn on/off rendering of the PseudoColor mapper for the given DataSet
     2826 */
     2827void Renderer::setPseudoColorVisibility(const DataSetId& id, bool state)
     2828{
     2829    PseudoColorHashmap::iterator itr;
     2830
     2831    bool doAll = false;
     2832
     2833    if (id.compare("all") == 0) {
     2834        itr = _pseudoColors.begin();
     2835        doAll = true;
     2836    } else {
     2837        itr = _pseudoColors.find(id);
     2838    }
     2839
     2840    if (itr == _pseudoColors.end()) {
     2841        ERROR("PseudoColor not found: %s", id.c_str());
     2842        return;
     2843    }
     2844
     2845    do {
     2846        itr->second->setVisibility(state);
     2847    } while (doAll && ++itr != _pseudoColors.end());
     2848
     2849    _needsRedraw = true;
     2850}
     2851
     2852/**
     2853 * \brief Set the visibility of polygon edges for the specified DataSet
     2854 */
     2855void Renderer::setPseudoColorEdgeVisibility(const DataSetId& id, bool state)
     2856{
     2857    PseudoColorHashmap::iterator itr;
     2858
     2859    bool doAll = false;
     2860
     2861    if (id.compare("all") == 0) {
     2862        itr = _pseudoColors.begin();
     2863        doAll = true;
     2864    } else {
     2865        itr = _pseudoColors.find(id);
     2866    }
     2867
     2868    if (itr == _pseudoColors.end()) {
     2869        ERROR("PseudoColor not found: %s", id.c_str());
     2870        return;
     2871    }
     2872
     2873    do {
     2874        itr->second->setEdgeVisibility(state);
     2875    } while (doAll && ++itr != _pseudoColors.end());
     2876
     2877    _needsRedraw = true;
     2878}
     2879
     2880/**
     2881 * \brief Set the RGB polygon edge color for the specified DataSet
     2882 */
     2883void Renderer::setPseudoColorEdgeColor(const DataSetId& id, float color[3])
     2884{
     2885    PseudoColorHashmap::iterator itr;
     2886
     2887    bool doAll = false;
     2888
     2889    if (id.compare("all") == 0) {
     2890        itr = _pseudoColors.begin();
     2891        doAll = true;
     2892    } else {
     2893        itr = _pseudoColors.find(id);
     2894    }
     2895
     2896    if (itr == _pseudoColors.end()) {
     2897        ERROR("PseudoColor not found: %s", id.c_str());
     2898        return;
     2899    }
     2900
     2901    do {
     2902        itr->second->setEdgeColor(color);
     2903    } while (doAll && ++itr != _pseudoColors.end());
     2904
     2905    _needsRedraw = true;
     2906}
     2907
     2908/**
     2909 * \brief Set the polygon edge width for the specified DataSet (may be a no-op)
     2910 *
     2911 * If the OpenGL implementation/hardware does not support wide lines,
     2912 * this function may not have an effect.
     2913 */
     2914void Renderer::setPseudoColorEdgeWidth(const DataSetId& id, float edgeWidth)
     2915{
     2916    PseudoColorHashmap::iterator itr;
     2917
     2918    bool doAll = false;
     2919
     2920    if (id.compare("all") == 0) {
     2921        itr = _pseudoColors.begin();
     2922        doAll = true;
     2923    } else {
     2924        itr = _pseudoColors.find(id);
     2925    }
     2926
     2927    if (itr == _pseudoColors.end()) {
     2928        ERROR("PseudoColor not found: %s", id.c_str());
     2929        return;
     2930    }
     2931
     2932    do {
     2933        itr->second->setEdgeWidth(edgeWidth);
     2934    } while (doAll && ++itr != _pseudoColors.end());
     2935
     2936    _needsRedraw = true;
     2937}
     2938
     2939/**
     2940 * \brief Turn mesh lighting on/off for the specified DataSet
     2941 */
     2942void Renderer::setPseudoColorLighting(const DataSetId& id, bool state)
     2943{
     2944    PseudoColorHashmap::iterator itr;
     2945
     2946    bool doAll = false;
     2947
     2948    if (id.compare("all") == 0) {
     2949        itr = _pseudoColors.begin();
     2950        doAll = true;
     2951    } else {
     2952        itr = _pseudoColors.find(id);
     2953    }
     2954
     2955    if (itr == _pseudoColors.end()) {
     2956        ERROR("PseudoColor not found: %s", id.c_str());
     2957        return;
     2958    }
     2959
     2960    do {
     2961        itr->second->setLighting(state);
     2962    } while (doAll && ++itr != _pseudoColors.end());
     2963
     2964    _needsRedraw = true;
     2965}
     2966
     2967/**
     2968 * \brief Create a new Volume and associate it with the named DataSet
     2969 */
     2970void Renderer::addVolume(const DataSetId& id)
     2971{
     2972    DataSetHashmap::iterator itr;
     2973
     2974    bool doAll = false;
     2975
     2976    if (id.compare("all") == 0) {
     2977        itr = _dataSets.begin();
     2978    } else {
     2979        itr = _dataSets.find(id);
     2980    }
     2981    if (itr == _dataSets.end()) {
     2982        ERROR("Unknown dataset %s", id.c_str());
     2983        return;
     2984    }
     2985
     2986    do {
     2987        DataSet *ds = itr->second;
     2988        const DataSetId& dsID = ds->getName();
     2989
     2990        if (getVolume(dsID)) {
     2991            WARN("Replacing existing volume %s", dsID.c_str());
     2992            deleteVolume(dsID);
     2993        }
     2994
     2995        Volume *volume = new Volume();
     2996        _volumes[dsID] = volume;
     2997
     2998        volume->setDataSet(ds);
     2999
     3000        if (_useCumulativeRange) {
     3001            ColorMap *cmap = volume->getColorMap();
     3002            volume->setColorMap(cmap, _cumulativeDataRange);
     3003        }
     3004
     3005        _renderer->AddViewProp(volume->getProp());
     3006    } while (doAll && ++itr != _dataSets.end());
     3007
     3008    if (_cameraMode == IMAGE)
     3009        setCameraMode(PERSPECTIVE);
     3010    initCamera();
     3011    _needsRedraw = true;
     3012}
     3013
     3014/**
     3015 * \brief Get the Volume associated with a named DataSet
     3016 */
     3017Volume *Renderer::getVolume(const DataSetId& id)
     3018{
     3019    VolumeHashmap::iterator itr = _volumes.find(id);
     3020
     3021    if (itr == _volumes.end()) {
     3022        TRACE("Volume not found: %s", id.c_str());
     3023        return NULL;
     3024    } else
     3025        return itr->second;
     3026}
     3027
     3028/**
     3029 * \brief Associate an existing named color map with a Volume for the given DataSet
     3030 */
     3031void Renderer::setVolumeColorMap(const DataSetId& id, const ColorMapId& colorMapId)
     3032{
     3033    VolumeHashmap::iterator itr;
     3034
     3035    bool doAll = false;
     3036
     3037    if (id.compare("all") == 0) {
     3038        itr = _volumes.begin();
     3039        doAll = true;
     3040    } else {
     3041        itr = _volumes.find(id);
     3042    }
     3043
     3044    if (itr == _volumes.end()) {
     3045        ERROR("Volume not found: %s", id.c_str());
     3046        return;
     3047    }
     3048
     3049    ColorMap *cmap = getColorMap(colorMapId);
     3050    if (cmap == NULL) {
     3051        ERROR("Unknown colormap: %s", colorMapId.c_str());
     3052        return;
     3053    }
     3054
     3055    do {
     3056        TRACE("Set Volume color map: %s for dataset %s", colorMapId.c_str(),
     3057              itr->second->getDataSet()->getName().c_str());
     3058
     3059        if (_useCumulativeRange) {
     3060            itr->second->setColorMap(cmap, _cumulativeDataRange);
     3061        } else {
     3062            itr->second->setColorMap(cmap);
     3063        }
     3064    } while (doAll && ++itr != _volumes.end());
     3065
     3066    _needsRedraw = true;
     3067}
     3068
     3069/**
     3070 * \brief Set Volume opacity scaling for the specified DataSet
     3071 */
     3072void Renderer::setVolumeOpacity(const DataSetId& id, double opacity)
     3073{
     3074    VolumeHashmap::iterator itr;
     3075
     3076    bool doAll = false;
     3077
     3078    if (id.compare("all") == 0) {
     3079        itr = _volumes.begin();
     3080        doAll = true;
     3081    } else {
     3082        itr = _volumes.find(id);
     3083    }
     3084    if (itr == _volumes.end()) {
     3085        ERROR("Volume not found: %s", id.c_str());
     3086        return;
     3087    }
     3088
     3089    do {
     3090        itr->second->setOpacity(opacity);
     3091    } while (doAll && ++itr != _volumes.end());
     3092
     3093    _needsRedraw = true;
     3094}
     3095
     3096/**
     3097 * \brief Turn on/off rendering of the Volume mapper for the given DataSet
     3098 */
     3099void Renderer::setVolumeVisibility(const DataSetId& id, bool state)
     3100{
     3101    VolumeHashmap::iterator itr;
     3102
     3103    bool doAll = false;
     3104
     3105    if (id.compare("all") == 0) {
     3106        itr = _volumes.begin();
     3107        doAll = true;
     3108    } else {
     3109        itr = _volumes.find(id);
     3110    }
     3111    if (itr == _volumes.end()) {
     3112        ERROR("Volume not found: %s", id.c_str());
     3113        return;
     3114    }
     3115
     3116    do {
     3117        itr->second->setVisibility(state);
     3118    } while (doAll && ++itr != _volumes.end());
     3119
     3120    _needsRedraw = true;
     3121}
     3122
     3123/**
     3124 * \brief Set volume ambient lighting/shading coefficient for the specified DataSet
     3125 */
     3126void Renderer::setVolumeAmbient(const DataSetId& id, double coeff)
     3127{
     3128    VolumeHashmap::iterator itr;
     3129
     3130    bool doAll = false;
     3131
     3132    if (id.compare("all") == 0) {
     3133        itr = _volumes.begin();
     3134        doAll = true;
     3135    } else {
     3136        itr = _volumes.find(id);
     3137    }
     3138    if (itr == _volumes.end()) {
     3139        ERROR("Volume not found: %s", id.c_str());
     3140        return;
     3141    }
     3142
     3143    do {
     3144        itr->second->setAmbient(coeff);
     3145    } while (doAll && ++itr != _volumes.end());
     3146
     3147    _needsRedraw = true;
     3148}
     3149
     3150/**
     3151 * \brief Set volume diffuse lighting/shading coefficient for the specified DataSet
     3152 */
     3153void Renderer::setVolumeDiffuse(const DataSetId& id, double coeff)
     3154{
     3155    VolumeHashmap::iterator itr;
     3156
     3157    bool doAll = false;
     3158
     3159    if (id.compare("all") == 0) {
     3160        itr = _volumes.begin();
     3161        doAll = true;
     3162    } else {
     3163        itr = _volumes.find(id);
     3164    }
     3165    if (itr == _volumes.end()) {
     3166        ERROR("Volume not found: %s", id.c_str());
     3167        return;
     3168    }
     3169
     3170    do {
     3171        itr->second->setDiffuse(coeff);
     3172    } while (doAll && ++itr != _volumes.end());
     3173
     3174    _needsRedraw = true;
     3175}
     3176
     3177/**
     3178 * \brief Set volume specular lighting/shading coefficient and power for the specified DataSet
     3179 */
     3180void Renderer::setVolumeSpecular(const DataSetId& id, double coeff, double power)
     3181{
     3182    VolumeHashmap::iterator itr;
     3183
     3184    bool doAll = false;
     3185
     3186    if (id.compare("all") == 0) {
     3187        itr = _volumes.begin();
     3188        doAll = true;
     3189    } else {
     3190        itr = _volumes.find(id);
     3191    }
     3192    if (itr == _volumes.end()) {
     3193        ERROR("Volume not found: %s", id.c_str());
     3194        return;
     3195    }
     3196
     3197    do {
     3198        itr->second->setSpecular(coeff, power);
     3199    } while (doAll && ++itr != _volumes.end());
     3200
     3201    _needsRedraw = true;
     3202}
     3203
     3204/**
     3205 * \brief Turn volume lighting/shading on/off for the specified DataSet
     3206 */
     3207void Renderer::setVolumeLighting(const DataSetId& id, bool state)
     3208{
     3209    VolumeHashmap::iterator itr;
     3210
     3211    bool doAll = false;
     3212
     3213    if (id.compare("all") == 0) {
     3214        itr = _volumes.begin();
     3215        doAll = true;
     3216    } else {
     3217        itr = _volumes.find(id);
     3218    }
     3219    if (itr == _volumes.end()) {
     3220        ERROR("Volume not found: %s", id.c_str());
     3221        return;
     3222    }
     3223
     3224    do {
     3225        itr->second->setLighting(state);
     3226    } while (doAll && ++itr != _volumes.end());
     3227
     3228    _needsRedraw = true;
     3229}
     3230
     3231/**
    15663232 * \brief Resize the render window (image size for renderings)
    15673233 */
    15683234void Renderer::setWindowSize(int width, int height)
    15693235{
     3236    // FIXME: Fix up panning on aspect change
     3237#ifdef notdef
     3238    if (_cameraPan[0] != 0.0) {
     3239        _cameraPan[0] *= ((double)_windowWidth / width);
     3240    }
     3241    if (_cameraPan[1] != 0.0) {
     3242        _cameraPan[1] *= ((double)_windowHeight / height);
     3243    }
     3244#endif
    15703245    _windowWidth = width;
    15713246    _windowHeight = height;
     
    16023277        camera->ParallelProjectionOn();
    16033278        if (origMode == IMAGE) {
    1604             resetCamera(false);
     3279            resetCamera(true);
    16053280        }
    16063281        break;
     
    16103285        camera->ParallelProjectionOff();
    16113286        if (origMode == IMAGE) {
    1612             resetCamera(false);
     3287            resetCamera(true);
    16133288        }
    16143289        break;
     
    16253300    }
    16263301    resetAxes();
     3302
    16273303    _needsRedraw = true;
    16283304}
     
    16363312}
    16373313
    1638 void Renderer::setSceneOrientation(double quat[4])
    1639 {
     3314/**
     3315 * \brief Set the orientation of the camera from a quaternion
     3316 *
     3317 * \param[in] quat A quaternion with scalar part first: w,x,y,z
     3318 */
     3319void Renderer::setCameraOrientation(double quat[4])
     3320{
     3321    if (_cameraMode == IMAGE)
     3322        return;
    16403323    vtkSmartPointer<vtkCamera> camera = _renderer->GetActiveCamera();
    16413324    vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
     
    16463329        memcpy((*mat4)[r], mat3[r], sizeof(double)*3);
    16473330    }
     3331    TRACE("Arcball camera matrix: %g %g %g %g %g %g %g %g %g",
     3332          (*mat4)[0][0], (*mat4)[0][1], (*mat4)[0][2],
     3333          (*mat4)[1][0], (*mat4)[1][1], (*mat4)[1][2],
     3334          (*mat4)[2][0], (*mat4)[2][1], (*mat4)[2][2]);
     3335    camera->SetPosition(0, 0, 1);
     3336    camera->SetFocalPoint(0, 0, 0);
     3337    camera->SetViewUp(0, 1, 0);
     3338    camera->SetViewAngle(30);
     3339    double bounds[6];
     3340    collectBounds(bounds, false);
     3341    _renderer->ResetCamera(bounds);
     3342    camera->GetFocalPoint(_cameraFocalPoint);
    16483343    trans->Translate(+_cameraFocalPoint[0], +_cameraFocalPoint[1], +_cameraFocalPoint[2]);
    16493344    trans->Concatenate(mat4);
    16503345    trans->Translate(-_cameraFocalPoint[0], -_cameraFocalPoint[1], -_cameraFocalPoint[2]);
    1651     camera->SetPosition(0, 0, 1);
    1652     camera->SetFocalPoint(0, 0, 0);
    1653     camera->SetViewUp(0, 1, 0);
    16543346    camera->ApplyTransform(trans);
    16553347    storeCameraOrientation();
     3348    if (_cameraZoomRatio != 1.0) {
     3349        double z = _cameraZoomRatio;
     3350        _cameraZoomRatio = 1.0;
     3351        zoomCamera(z, true);
     3352    }
    16563353    if (_cameraPan[0] != 0.0 || _cameraPan[1] != 0.0) {
    1657         panCamera(_cameraPan[0], _cameraPan[1], true);
    1658     }
    1659     _needsRedraw = true;
    1660 }
    1661 
     3354        double panx = _cameraPan[0];
     3355        double pany = -_cameraPan[1];
     3356        _cameraPan[0] = 0;
     3357        _cameraPan[1] = 0;
     3358        panCamera(panx, pany, true);
     3359    }
     3360    _renderer->ResetCameraClippingRange();
     3361    printCameraInfo(camera);
     3362    _needsRedraw = true;
     3363}
     3364
     3365/**
     3366 * \brief Set the position and orientation of the camera
     3367 *
     3368 * \param[in] position x,y,z position of camera in world coordinates
     3369 * \param[in] focalPoint x,y,z look-at point in world coordinates
     3370 * \param[in] viewUp x,y,z up vector of camera
     3371 */
    16623372void Renderer::setCameraOrientationAndPosition(double position[3],
    16633373                                               double focalPoint[3],
     
    16723382}
    16733383
     3384/**
     3385 * \brief Get the position and orientation of the camera
     3386 *
     3387 * \param[out] position x,y,z position of camera in world coordinates
     3388 * \param[out] focalPoint x,y,z look-at point in world coordinates
     3389 * \param[out] viewUp x,y,z up vector of camera
     3390 */
    16743391void Renderer::getCameraOrientationAndPosition(double position[3],
    16753392                                               double focalPoint[3],
     
    16813398}
    16823399
     3400/**
     3401 * \brief Saves the current camera orientation and position in order to
     3402 * be able to later restore the saved orientation and position
     3403 */
    16833404void Renderer::storeCameraOrientation()
    16843405{
     
    16893410}
    16903411
     3412/**
     3413 * \brief Use the stored orientation and position to set the camera's
     3414 * current state
     3415 */
    16913416void Renderer::restoreCameraOrientation()
    16923417{
     
    17043429void Renderer::resetCamera(bool resetOrientation)
    17053430{
     3431    vtkSmartPointer<vtkCamera> camera = _renderer->GetActiveCamera();
    17063432    if (_cameraMode == IMAGE) {
    17073433        initCamera();
    17083434    } else {
    17093435        if (resetOrientation) {
    1710             vtkSmartPointer<vtkCamera> camera = _renderer->GetActiveCamera();
    17113436            camera->SetPosition(0, 0, 1);
    17123437            camera->SetFocalPoint(0, 0, 0);
     
    17163441            restoreCameraOrientation();
    17173442        }
    1718         _renderer->ResetCamera();
     3443        camera->SetViewAngle(30);
     3444        double bounds[6];
     3445        collectBounds(bounds, false);
     3446        _renderer->ResetCamera(bounds);
    17193447        _renderer->ResetCameraClippingRange();
    17203448        computeScreenWorldCoords();
    17213449    }
     3450
     3451    printCameraInfo(camera);
     3452
    17223453    _cameraZoomRatio = 1;
    17233454    _cameraPan[0] = 0;
     
    17613492void Renderer::panCamera(double x, double y, bool absolute)
    17623493{
     3494    TRACE("Enter panCamera: %g %g, current abs: %g %g",
     3495          x, y, _cameraPan[0], _cameraPan[1]);
     3496
    17633497    if (_cameraMode == IMAGE) {
    17643498        // Reverse x rather than y, since we are panning the camera, and client
     
    18173551                              focalDepth,
    18183552                              oldPickPoint);
    1819  
     3553
    18203554        // Camera motion is reversed
    18213555        motionVector[0] = oldPickPoint[0] - newPickPoint[0];
     
    18353569        _renderer->ResetCameraClippingRange();
    18363570        storeCameraOrientation();
    1837         computeScreenWorldCoords();
    1838     }
     3571        //computeScreenWorldCoords();
     3572    }
     3573
     3574    TRACE("Leave panCamera: %g %g, current abs: %g %g",
     3575          x, y, _cameraPan[0], _cameraPan[1]);
     3576
    18393577    _needsRedraw = true;
    18403578}
     
    18483586void Renderer::zoomCamera(double z, bool absolute)
    18493587{
     3588    vtkSmartPointer<vtkCamera> camera = _renderer->GetActiveCamera();
     3589    TRACE("Enter Zoom: current abs: %g, z: %g, view angle %g",
     3590          _cameraZoomRatio, z, camera->GetViewAngle());
     3591
    18503592    if (absolute) {
    18513593        assert(_cameraZoomRatio > 0.0);
     
    18563598        _cameraZoomRatio *= z;
    18573599    }
     3600
    18583601    if (_cameraMode == IMAGE) {
    18593602        double dx = _imgWorldDims[0];
     
    18683611                            _imgWorldDims[0], _imgWorldDims[1]);
    18693612    } else {
    1870         vtkSmartPointer<vtkCamera> camera = _renderer->GetActiveCamera();
    18713613        camera->Zoom(z); // Change perspective FOV angle or ortho parallel scale
    18723614        //camera->Dolly(z); // Move camera forward/back
    18733615        _renderer->ResetCameraClippingRange();
    18743616        storeCameraOrientation();
    1875     }
     3617        //computeScreenWorldCoords();
     3618    }
     3619
     3620    TRACE("Leave Zoom: rel %g, new abs: %g, view angle %g",
     3621          z, _cameraZoomRatio, camera->GetViewAngle());
     3622
    18763623    _needsRedraw = true;
    18773624}
     
    19353682
    19363683    // bottom
    1937     _clippingPlanes->GetItem(0)->SetOrigin(0, _imgWorldOrigin[1], 0);
     3684    _clipPlanes[0]->SetOrigin(0, _imgWorldOrigin[1], 0);
    19383685    // left
    1939     _clippingPlanes->GetItem(1)->SetOrigin(_imgWorldOrigin[0], 0, 0);
     3686    _clipPlanes[1]->SetOrigin(_imgWorldOrigin[0], 0, 0);
    19403687    // top
    1941     _clippingPlanes->GetItem(2)->SetOrigin(0, _imgWorldOrigin[1] + _imgWorldDims[1], 0);
     3688    _clipPlanes[2]->SetOrigin(0, _imgWorldOrigin[1] + _imgWorldDims[1], 0);
    19423689    // right
    1943     _clippingPlanes->GetItem(3)->SetOrigin(_imgWorldOrigin[0] + _imgWorldDims[0], 0, 0);
     3690    _clipPlanes[3]->SetOrigin(_imgWorldOrigin[0] + _imgWorldDims[0], 0, 0);
    19443691
    19453692    _cubeAxesActor2D->SetBounds(_imgWorldOrigin[0], _imgWorldOrigin[0] + _imgWorldDims[0],
     
    19563703}
    19573704
     3705/**
     3706 * \brief Convert pixel/display coordinates to world coordinates based on current camera
     3707 */
    19583708void Renderer::computeDisplayToWorld(double x, double y, double z, double worldPt[4])
    19593709{
     
    19693719}
    19703720
     3721/**
     3722 * \brief Convert world coordinates to pixel/display coordinates based on current camera
     3723 */
    19713724void Renderer::computeWorldToDisplay(double x, double y, double z, double displayPt[3])
    19723725{
     
    19763729}
    19773730
     3731/**
     3732 * \brief Compute the world coordinate bounds of the display rectangle
     3733 */
    19783734void Renderer::computeScreenWorldCoords()
    19793735{
     
    20663822                           const double *bounds1, const double *bounds2)
    20673823{
     3824    assert(boundsDest != NULL);
     3825    assert(bounds1 != NULL);
     3826    if (bounds2 == NULL) {
     3827        WARN("NULL bounds2 array");
     3828        return;
     3829    }
    20683830    for (int i = 0; i < 6; i++) {
    20693831        if (i % 2 == 0)
     
    20893851    bounds[5] = -DBL_MAX;
    20903852
     3853    for (Contour2DHashmap::iterator itr = _contour2Ds.begin();
     3854             itr != _contour2Ds.end(); ++itr) {
     3855        if (!onlyVisible || itr->second->getVisibility())
     3856            mergeBounds(bounds, bounds, itr->second->getProp()->GetBounds());
     3857    }
     3858    for (Contour3DHashmap::iterator itr = _contour3Ds.begin();
     3859             itr != _contour3Ds.end(); ++itr) {
     3860        if (!onlyVisible || itr->second->getVisibility())
     3861            mergeBounds(bounds, bounds, itr->second->getProp()->GetBounds());
     3862    }
     3863    for (GlyphsHashmap::iterator itr = _glyphs.begin();
     3864             itr != _glyphs.end(); ++itr) {
     3865        if (!onlyVisible || itr->second->getVisibility())
     3866            mergeBounds(bounds, bounds, itr->second->getProp()->GetBounds());
     3867    }
     3868    for (HeightMapHashmap::iterator itr = _heightMaps.begin();
     3869             itr != _heightMaps.end(); ++itr) {
     3870        if (!onlyVisible || itr->second->getVisibility())
     3871            mergeBounds(bounds, bounds, itr->second->getProp()->GetBounds());
     3872    }
     3873    for (PolyDataHashmap::iterator itr = _polyDatas.begin();
     3874             itr != _polyDatas.end(); ++itr) {
     3875        if (!onlyVisible || itr->second->getVisibility())
     3876            mergeBounds(bounds, bounds, itr->second->getProp()->GetBounds());
     3877    }
    20913878    for (PseudoColorHashmap::iterator itr = _pseudoColors.begin();
    20923879             itr != _pseudoColors.end(); ++itr) {
    20933880        if (!onlyVisible || itr->second->getVisibility())
    2094             mergeBounds(bounds, bounds, itr->second->getActor()->GetBounds());
    2095     }
    2096     for (Contour2DHashmap::iterator itr = _contours.begin();
    2097              itr != _contours.end(); ++itr) {
     3881            mergeBounds(bounds, bounds, itr->second->getProp()->GetBounds());
     3882    }
     3883    for (VolumeHashmap::iterator itr = _volumes.begin();
     3884             itr != _volumes.end(); ++itr) {
    20983885        if (!onlyVisible || itr->second->getVisibility())
    2099             mergeBounds(bounds, bounds, itr->second->getActor()->GetBounds());
    2100     }
    2101     for (PolyDataHashmap::iterator itr = _polyDatas.begin();
    2102              itr != _polyDatas.end(); ++itr) {
    2103         if (!onlyVisible || itr->second->getVisibility())
    2104             mergeBounds(bounds, bounds, itr->second->getActor()->GetBounds());
     3886            mergeBounds(bounds, bounds, itr->second->getProp()->GetBounds());
    21053887    }
    21063888    for (int i = 0; i < 6; i++) {
     
    21133895        }
    21143896    }
     3897    TRACE("Bounds: %g %g %g %g %g %g",
     3898          bounds[0],
     3899          bounds[1],
     3900          bounds[2],
     3901          bounds[3],
     3902          bounds[4],
     3903          bounds[5]);
    21153904}
    21163905
     
    21223911void Renderer::updateRanges(bool useCumulative)
    21233912{
     3913    for (Contour2DHashmap::iterator itr = _contour2Ds.begin();
     3914         itr != _contour2Ds.end(); ++itr) {
     3915        // Only need to update range if using evenly spaced contours
     3916        if (itr->second->getContourList().empty()) {
     3917            if (useCumulative) {
     3918                itr->second->setContours(itr->second->getNumContours(), _cumulativeDataRange);
     3919            } else {
     3920                itr->second->setContours(itr->second->getNumContours());
     3921            }
     3922        }
     3923    }
     3924    for (Contour3DHashmap::iterator itr = _contour3Ds.begin();
     3925         itr != _contour3Ds.end(); ++itr) {
     3926        // Only need to update range if using evenly spaced contours
     3927        if (itr->second->getContourList().empty()) {
     3928            if (useCumulative) {
     3929                itr->second->setContours(itr->second->getNumContours(), _cumulativeDataRange);
     3930            } else {
     3931                itr->second->setContours(itr->second->getNumContours());
     3932            }
     3933        }
     3934    }
     3935    for (GlyphsHashmap::iterator itr = _glyphs.begin();
     3936         itr != _glyphs.end(); ++itr) {
     3937        vtkLookupTable *lut = itr->second->getLookupTable();
     3938        if (lut) {
     3939            if (useCumulative) {
     3940                lut->SetRange(_cumulativeDataRange);
     3941            } else {
     3942                double range[2];
     3943                if (itr->second->getDataSet()) {
     3944                    itr->second->getDataSet()->getDataRange(range);
     3945                    lut->SetRange(range);
     3946                }
     3947            }
     3948        }
     3949    }
     3950    for (HeightMapHashmap::iterator itr = _heightMaps.begin();
     3951         itr != _heightMaps.end(); ++itr) {
     3952        vtkLookupTable *lut = itr->second->getLookupTable();
     3953        if (lut) {
     3954            if (useCumulative) {
     3955                lut->SetRange(_cumulativeDataRange);
     3956            } else {
     3957                double range[2];
     3958                if (itr->second->getDataSet()) {
     3959                    itr->second->getDataSet()->getDataRange(range);
     3960                    lut->SetRange(range);
     3961                }
     3962            }
     3963        }
     3964        // Only need to update contour range if using evenly spaced contours
     3965        if (itr->second->getContourList().empty()) {
     3966            if (useCumulative) {
     3967                itr->second->setContours(itr->second->getNumContours(), _cumulativeDataRange);
     3968            } else {
     3969                itr->second->setContours(itr->second->getNumContours());
     3970            }
     3971        }
     3972    }
    21243973    for (PseudoColorHashmap::iterator itr = _pseudoColors.begin();
    21253974         itr != _pseudoColors.end(); ++itr) {
     
    21373986        }
    21383987    }
    2139     for (Contour2DHashmap::iterator itr = _contours.begin();
    2140          itr != _contours.end(); ++itr) {
    2141         // Only need to update range if using evenly spaced contours
    2142         if (itr->second->getContourList().empty()) {
     3988    for (VolumeHashmap::iterator itr = _volumes.begin();
     3989         itr != _volumes.end(); ++itr) {
     3990        ColorMap *cmap = itr->second->getColorMap();
     3991        if (cmap) {
    21433992            if (useCumulative) {
    2144                 itr->second->setContours(itr->second->getNumContours(), _cumulativeDataRange);
     3993                itr->second->setColorMap(cmap, _cumulativeDataRange);
    21453994            } else {
    2146                 itr->second->setContours(itr->second->getNumContours());
     3995                itr->second->setColorMap(cmap);
    21473996            }
    21483997        }
     
    21764025}
    21774026
    2178 #ifdef notdef
    2179 void Renderer::setPerspectiveCameraByBounds(double bounds[6])
    2180 {
    2181     vtkSmartPointer<vtkCamera> camera = _renderer->GetActiveCamera();
    2182     camera->ParallelProjectionOff();
    2183     camera->Reset();
    2184 }
     4027/**
     4028 * \brief Initialize the camera zoom region to include the bounding volume given
     4029 */
     4030void Renderer::initCamera()
     4031{
     4032#ifdef WANT_TRACE
     4033    switch (_cameraMode) {
     4034    case IMAGE:
     4035        TRACE("Image camera");
     4036        break;
     4037    case ORTHO:
     4038        TRACE("Ortho camera");
     4039        break;
     4040    case PERSPECTIVE:
     4041        TRACE("Perspective camera");
     4042        break;
     4043    default:
     4044        TRACE("Unknown camera mode");
     4045    }
    21854046#endif
    2186 
    2187 /**
    2188  * \brief Initialize the camera zoom region to include the bounding volume given
    2189  */
    2190 void Renderer::initCamera()
    2191 {
    21924047    double bounds[6];
    2193     collectBounds(bounds, true);
     4048    collectBounds(bounds, false);
    21944049    _imgWorldOrigin[0] = bounds[0];
    21954050    _imgWorldOrigin[1] = bounds[2];
     
    22004055    _cameraZoomRatio = 1;
    22014056
    2202     if (_cameraMode == IMAGE) {
    2203         _renderer->ResetCamera();
     4057    switch (_cameraMode) {
     4058    case IMAGE:
     4059        _renderer->ResetCamera(bounds);
    22044060        setCameraZoomRegion(_imgWorldOrigin[0], _imgWorldOrigin[1],
    22054061                            _imgWorldDims[0], _imgWorldDims[1]);
    22064062        resetAxes();
    2207     } else if (_cameraMode == ORTHO) {
     4063        break;
     4064    case ORTHO:
    22084065        _renderer->GetActiveCamera()->ParallelProjectionOn();
    22094066        resetAxes();
    2210         _renderer->ResetCamera();
     4067        _renderer->ResetCamera(bounds);
    22114068        computeScreenWorldCoords();
    2212     } else if (_cameraMode == PERSPECTIVE) {
     4069        break;
     4070    case PERSPECTIVE:
    22134071        _renderer->GetActiveCamera()->ParallelProjectionOff();
    22144072        resetAxes();
    2215         _renderer->ResetCamera();
     4073        _renderer->ResetCamera(bounds);
    22164074        computeScreenWorldCoords();
    2217     }
     4075        break;
     4076    default:
     4077        ERROR("Unknown camera mode");
     4078    }
     4079#ifdef WANT_TRACE
     4080    printCameraInfo(_renderer->GetActiveCamera());
     4081#endif
    22184082}
    22194083
     
    22234087void Renderer::printCameraInfo(vtkCamera *camera)
    22244088{
    2225     TRACE("Parallel Scale: %g, Cam pos: %g %g %g, focal pt: %g %g %g, view up: %g %g %g, Clipping range: %g %g",
     4089    TRACE("Parallel Scale: %g, View angle: %g, Cam pos: %g %g %g, focal pt: %g %g %g, view up: %g %g %g, Clipping range: %g %g",
    22264090          camera->GetParallelScale(),
     4091          camera->GetViewAngle(),
    22274092          camera->GetPosition()[0],
    22284093          camera->GetPosition()[1],
     
    22554120void Renderer::setOpacity(const DataSetId& id, double opacity)
    22564121{
    2257     setPseudoColorOpacity(id, opacity);
    2258     setContourOpacity(id, opacity);
    2259     setPolyDataOpacity(id, opacity);
     4122    if (id.compare("all") == 0 || getContour2D(id) != NULL)
     4123        setContour2DOpacity(id, opacity);
     4124    if (id.compare("all") == 0 || getContour3D(id) != NULL)
     4125        setContour3DOpacity(id, opacity);
     4126    if (id.compare("all") == 0 || getGlyphs(id) != NULL)
     4127        setGlyphsOpacity(id, opacity);
     4128    if (id.compare("all") == 0 || getHeightMap(id) != NULL)
     4129        setHeightMapOpacity(id, opacity);
     4130    if (id.compare("all") == 0 || getPolyData(id) != NULL)
     4131        setPolyDataOpacity(id, opacity);
     4132    if (id.compare("all") == 0 || getPseudoColor(id) != NULL)
     4133        setPseudoColorOpacity(id, opacity);
     4134    if (id.compare("all") == 0 || getVolume(id) != NULL)
     4135        setVolumeOpacity(id, opacity);
    22604136}
    22614137
     
    22844160    } while (doAll && ++itr != _dataSets.end());
    22854161
    2286     setPseudoColorVisibility(id, state);
    2287     setContourVisibility(id, state);
    2288     setPolyDataVisibility(id, state);
     4162    if (id.compare("all") == 0 || getContour2D(id) != NULL)
     4163        setContour2DVisibility(id, state);
     4164    if (id.compare("all") == 0 || getContour3D(id) != NULL)
     4165        setContour3DVisibility(id, state);
     4166    if (id.compare("all") == 0 || getGlyphs(id) != NULL)
     4167        setGlyphsVisibility(id, state);
     4168    if (id.compare("all") == 0 || getHeightMap(id) != NULL)
     4169        setHeightMapVisibility(id, state);
     4170    if (id.compare("all") == 0 || getPolyData(id) != NULL)
     4171        setPolyDataVisibility(id, state);
     4172    if (id.compare("all") == 0 || getPseudoColor(id) != NULL)
     4173        setPseudoColorVisibility(id, state);
     4174    if (id.compare("all") == 0 || getVolume(id) != NULL)
     4175        setVolumeVisibility(id, state);
     4176}
     4177
     4178/**
     4179 * \brief Set up clipping planes for image camera mode if needed
     4180 */
     4181void Renderer::setCameraClippingPlanes()
     4182{
     4183    /* XXX: Note that there appears to be a bug with setting the
     4184     * clipping plane collection to NULL in the VTK Mappers --
     4185     * the old clip planes are still applied.  The workaround here
     4186     * is to keep the PlaneCollection and add/remove the planes
     4187     * to/from the PlaneCollection as needed.
     4188     */
     4189    if (_cameraMode == IMAGE) {
     4190        if (_activeClipPlanes->GetNumberOfItems() == 0) {
     4191            for (int i = 0; i < 4; i++)
     4192                _activeClipPlanes->AddItem(_clipPlanes[i]);
     4193        }
     4194    } else {
     4195        if (_activeClipPlanes->GetNumberOfItems() > 0)
     4196            _activeClipPlanes->RemoveAllItems();
     4197    }
     4198
     4199    /* Ensure all Mappers are using the PlaneCollection
     4200     * This will not change the state or timestamp of
     4201     * Mappers already using the PlaneCollection
     4202     */
     4203    for (Contour2DHashmap::iterator itr = _contour2Ds.begin();
     4204         itr != _contour2Ds.end(); ++itr) {
     4205        itr->second->setClippingPlanes(_activeClipPlanes);
     4206    }
     4207    for (Contour3DHashmap::iterator itr = _contour3Ds.begin();
     4208         itr != _contour3Ds.end(); ++itr) {
     4209        itr->second->setClippingPlanes(_activeClipPlanes);
     4210    }
     4211    for (GlyphsHashmap::iterator itr = _glyphs.begin();
     4212         itr != _glyphs.end(); ++itr) {
     4213        itr->second->setClippingPlanes(_activeClipPlanes);
     4214    }
     4215    for (HeightMapHashmap::iterator itr = _heightMaps.begin();
     4216         itr != _heightMaps.end(); ++itr) {
     4217        itr->second->setClippingPlanes(_activeClipPlanes);
     4218    }
     4219    for (PolyDataHashmap::iterator itr = _polyDatas.begin();
     4220         itr != _polyDatas.end(); ++itr) {
     4221        itr->second->setClippingPlanes(_activeClipPlanes);
     4222    }
     4223    for (PseudoColorHashmap::iterator itr = _pseudoColors.begin();
     4224         itr != _pseudoColors.end(); ++itr) {
     4225        itr->second->setClippingPlanes(_activeClipPlanes);
     4226    }
     4227    for (VolumeHashmap::iterator itr = _volumes.begin();
     4228         itr != _volumes.end(); ++itr) {
     4229        itr->second->setClippingPlanes(_activeClipPlanes);
     4230    }
     4231}
     4232
     4233/**
     4234 * \brief Control the use of the depth peeling algorithm for transparency
     4235 */
     4236void Renderer::setUseDepthPeeling(bool state)
     4237{
     4238    _renderer->SetUseDepthPeeling(state ? 1 : 0);
     4239    _needsRedraw = true;
    22894240}
    22904241
     
    22984249{
    22994250    if (_needsRedraw) {
    2300         if (_cameraMode == IMAGE) {
    2301             for (PseudoColorHashmap::iterator itr = _pseudoColors.begin();
    2302                  itr != _pseudoColors.end(); ++itr) {
    2303                 itr->second->setClippingPlanes(_clippingPlanes);
    2304             }
    2305             for (Contour2DHashmap::iterator itr = _contours.begin();
    2306                  itr != _contours.end(); ++itr) {
    2307                 itr->second->setClippingPlanes(_clippingPlanes);
    2308             }
    2309             for (PolyDataHashmap::iterator itr = _polyDatas.begin();
    2310                  itr != _polyDatas.end(); ++itr) {
    2311                 itr->second->setClippingPlanes(_clippingPlanes);
    2312             }
    2313         } else {
    2314             for (PseudoColorHashmap::iterator itr = _pseudoColors.begin();
    2315                  itr != _pseudoColors.end(); ++itr) {
    2316                 itr->second->setClippingPlanes(NULL);
    2317             }
    2318             for (Contour2DHashmap::iterator itr = _contours.begin();
    2319                  itr != _contours.end(); ++itr) {
    2320                 itr->second->setClippingPlanes(NULL);
    2321             }
    2322             for (PolyDataHashmap::iterator itr = _polyDatas.begin();
    2323                  itr != _polyDatas.end(); ++itr) {
    2324                 itr->second->setClippingPlanes(NULL);
    2325             }
    2326         }
     4251        setCameraClippingPlanes();
    23274252        _renderWindow->Render();
    23284253        _needsRedraw = false;
     
    23494274void Renderer::getRenderedFrame(vtkUnsignedCharArray *imgData)
    23504275{
    2351     _renderWindow->GetPixelData(0, 0, _windowWidth-1, _windowHeight-1, 1, imgData);
     4276#ifdef RENDER_TARGA
     4277    _renderWindow->MakeCurrent();
     4278    // Must clear previous errors first.
     4279    while (glGetError() != GL_NO_ERROR){
     4280        ;
     4281    }
     4282    int bytesPerPixel = TARGA_BYTES_PER_PIXEL;
     4283    int size = bytesPerPixel * _windowWidth * _windowHeight;
     4284
     4285    if (imgData->GetMaxId() + 1 != size)
     4286    {
     4287        imgData->SetNumberOfComponents(bytesPerPixel);
     4288        imgData->SetNumberOfValues(size);
     4289    }
     4290    glDisable(GL_TEXTURE_2D);
     4291    if (_renderWindow->GetDoubleBuffer()) {
     4292        glReadBuffer(static_cast<GLenum>(vtkOpenGLRenderWindow::SafeDownCast(_renderWindow)->GetBackLeftBuffer()));
     4293    } else {
     4294        glReadBuffer(static_cast<GLenum>(vtkOpenGLRenderWindow::SafeDownCast(_renderWindow)->GetFrontLeftBuffer()));
     4295    }
     4296    glPixelStorei(GL_PACK_ALIGNMENT, 1);
     4297#ifdef WANT_TRACE
     4298    struct timeval t1, t2;
     4299    glFinish();
     4300    gettimeofday(&t1, 0);
     4301#endif
     4302    if (bytesPerPixel == 4) {
     4303        glReadPixels(0, 0, _windowWidth, _windowHeight, GL_BGRA,
     4304                     GL_UNSIGNED_BYTE, imgData->GetPointer(0));
     4305    } else {
     4306        glReadPixels(0, 0, _windowWidth, _windowHeight, GL_BGR,
     4307                     GL_UNSIGNED_BYTE, imgData->GetPointer(0));
     4308    }
     4309#ifdef WANT_TRACE
     4310    gettimeofday(&t2, 0);
     4311    static unsigned int numFrames = 0;
     4312    static double accum = 0;
     4313    numFrames++;
     4314    accum += ELAPSED_TIME(t1, t2);
     4315#endif
     4316    TRACE("Readback time: %g ms", ELAPSED_TIME(t1, t2));
     4317    TRACE("Readback avg: %g ms", accum/numFrames);
     4318    if (glGetError() != GL_NO_ERROR) {
     4319        ERROR("glReadPixels");
     4320    }
     4321#else
     4322    _renderWindow->GetPixelData(0, 0, _windowWidth-1, _windowHeight-1,
     4323                                !_renderWindow->GetDoubleBuffer(), imgData);
     4324#endif
    23524325    TRACE("Image data size: %d", imgData->GetSize());
    23534326}
  • branches/blt4/packages/vizservers/vtkvis/RpVtkRenderer.h

    r2215 r2302  
    1010
    1111#include <vtkSmartPointer.h>
    12 #include <vtkLookupTable.h>
    1312#include <vtkCubeAxesActor.h>
    1413#ifdef USE_CUSTOM_AXES
     
    2827#include "ColorMap.h"
    2928#include "RpVtkDataSet.h"
     29#include "RpContour2D.h"
     30#include "RpContour3D.h"
     31#include "RpGlyphs.h"
     32#include "RpHeightMap.h"
     33#include "RpPolyData.h"
    3034#include "RpPseudoColor.h"
    31 #include "RpContour2D.h"
    32 #include "RpPolyData.h"
     35#include "RpVolume.h"
     36#include "Trace.h"
     37
     38// Controls if TGA format is sent to client
     39//#define RENDER_TARGA
     40#define TARGA_BYTES_PER_PIXEL 3
    3341
    3442namespace Rappture {
     
    5058    };
    5159
     60    enum AxesFlyMode {
     61        FLY_OUTER_EDGES = 0,
     62        FLY_CLOSEST_TRIAD,
     63        FLY_FURTHEST_TRIAD,
     64        FLY_STATIC_EDGES,
     65        FLY_STATIC_TRIAD
     66    };
     67
    5268    enum CameraMode {
    5369        PERSPECTIVE,
     
    6076    typedef std::tr1::unordered_map<DataSetId, DataSet *> DataSetHashmap;
    6177    typedef std::tr1::unordered_map<ColorMapId, ColorMap *> ColorMapHashmap;
     78    typedef std::tr1::unordered_map<DataSetId, Contour2D *> Contour2DHashmap;
     79    typedef std::tr1::unordered_map<DataSetId, Contour3D *> Contour3DHashmap;
     80    typedef std::tr1::unordered_map<DataSetId, Glyphs *> GlyphsHashmap;
     81    typedef std::tr1::unordered_map<DataSetId, HeightMap *> HeightMapHashmap;
     82    typedef std::tr1::unordered_map<DataSetId, PolyData *> PolyDataHashmap;
    6283    typedef std::tr1::unordered_map<DataSetId, PseudoColor *> PseudoColorHashmap;
    63     typedef std::tr1::unordered_map<DataSetId, Contour2D *> Contour2DHashmap;
    64     typedef std::tr1::unordered_map<DataSetId, PolyData *> PolyDataHashmap;
     84    typedef std::tr1::unordered_map<DataSetId, Volume *> VolumeHashmap;
    6585
    6686    // Data sets
     
    110130    void rotateCamera(double yaw, double pitch, double roll);
    111131
    112     void setSceneOrientation(double quat[4]);
     132    void setCameraOrientation(double quat[4]);
    113133
    114134    void setCameraOrientationAndPosition(double position[3],
     
    128148    void setBackgroundColor(float color[3]);
    129149
     150    void setUseDepthPeeling(bool state);
     151
    130152    bool render();
    131153
     
    133155
    134156    // Axes
     157
     158    void setAxesFlyMode(AxesFlyMode mode);
    135159
    136160    void setAxesGridVisibility(bool state);
     
    162186                        vtkUnsignedCharArray *imgData);
    163187
    164     // Color-mapped surfaces
    165 
    166     void addPseudoColor(const DataSetId& id);
    167 
    168     void deletePseudoColor(const DataSetId& id);
    169 
    170     PseudoColor *getPseudoColor(const DataSetId& id);
    171 
    172     void setPseudoColorColorMap(const DataSetId& id, const ColorMapId& colorMapId);
    173 
    174     vtkLookupTable *getPseudoColorColorMap(const DataSetId& id);
    175 
    176     void setPseudoColorOpacity(const DataSetId& id, double opacity);
    177 
    178     void setPseudoColorVisibility(const DataSetId& id, bool state);
    179 
    180     void setPseudoColorEdgeVisibility(const DataSetId& id, bool state);
    181 
    182     void setPseudoColorEdgeColor(const DataSetId& id, float color[3]);
    183 
    184     void setPseudoColorEdgeWidth(const DataSetId& id, float edgeWidth);
    185 
    186     void setPseudoColorLighting(const DataSetId& id, bool state);
    187 
    188     // Contour plots
     188    // 2D Contour plots
    189189
    190190    void addContour2D(const DataSetId& id);
     
    194194    Contour2D *getContour2D(const DataSetId& id);
    195195
    196     void setContours(const DataSetId& id, int numContours);
    197 
    198     void setContourList(const DataSetId& id, const std::vector<double>& contours);
    199 
    200     void setContourOpacity(const DataSetId& id, double opacity);
    201 
    202     void setContourVisibility(const DataSetId& id, bool state);
    203 
    204     void setContourEdgeColor(const DataSetId& id, float color[3]);
    205 
    206     void setContourEdgeWidth(const DataSetId& id, float edgeWidth);
    207 
    208     void setContourLighting(const DataSetId& id, bool state);
     196    void setContour2DContours(const DataSetId& id, int numContours);
     197
     198    void setContour2DContourList(const DataSetId& id, const std::vector<double>& contours);
     199
     200    void setContour2DOpacity(const DataSetId& id, double opacity);
     201
     202    void setContour2DVisibility(const DataSetId& id, bool state);
     203
     204    void setContour2DEdgeColor(const DataSetId& id, float color[3]);
     205
     206    void setContour2DEdgeWidth(const DataSetId& id, float edgeWidth);
     207
     208    void setContour2DLighting(const DataSetId& id, bool state);
     209
     210    // 3D Contour (isosurface) plots
     211
     212    void addContour3D(const DataSetId& id);
     213
     214    void deleteContour3D(const DataSetId& id);
     215
     216    Contour3D *getContour3D(const DataSetId& id);
     217
     218    void setContour3DContours(const DataSetId& id, int numContours);
     219
     220    void setContour3DContourList(const DataSetId& id, const std::vector<double>& contours);
     221
     222    void setContour3DColorMap(const DataSetId& id, const ColorMapId& colorMapId);
     223
     224    void setContour3DOpacity(const DataSetId& id, double opacity);
     225
     226    void setContour3DVisibility(const DataSetId& id, bool state);
     227
     228    void setContour3DColor(const DataSetId& id, float color[3]);
     229
     230    void setContour3DEdgeVisibility(const DataSetId& id, bool state);
     231
     232    void setContour3DEdgeColor(const DataSetId& id, float color[3]);
     233
     234    void setContour3DEdgeWidth(const DataSetId& id, float edgeWidth);
     235
     236    void setContour3DWireframe(const DataSetId& id, bool state);
     237
     238    void setContour3DLighting(const DataSetId& id, bool state);
     239
     240    // Glyphs
     241
     242    void addGlyphs(const DataSetId& id);
     243
     244    void deleteGlyphs(const DataSetId& id);
     245
     246    Glyphs *getGlyphs(const DataSetId& id);
     247
     248    void setGlyphsColorMap(const DataSetId& id, const ColorMapId& colorMapId);
     249
     250    void setGlyphsShape(const DataSetId& id, Glyphs::GlyphShape shape);
     251
     252    void setGlyphsScaleFactor(const DataSetId& id, double scale);
     253
     254    void setGlyphsOpacity(const DataSetId& id, double opacity);
     255
     256    void setGlyphsVisibility(const DataSetId& id, bool state);
     257
     258    void setGlyphsLighting(const DataSetId& id, bool state);
     259
     260    // Height maps
     261
     262    void addHeightMap(const DataSetId& id);
     263
     264    void deleteHeightMap(const DataSetId& id);
     265
     266    HeightMap *getHeightMap(const DataSetId& id);
     267
     268    void setHeightMapVolumeSlice(const DataSetId& id, HeightMap::Axis axis, double ratio);
     269
     270    void setHeightMapHeightScale(const DataSetId& id, double scale);
     271
     272    void setHeightMapColorMap(const DataSetId& id, const ColorMapId& colorMapId);
     273
     274    void setHeightMapContours(const DataSetId& id, int numContours);
     275
     276    void setHeightMapContourList(const DataSetId& id, const std::vector<double>& contours);
     277
     278    void setHeightMapOpacity(const DataSetId& id, double opacity);
     279
     280    void setHeightMapVisibility(const DataSetId& id, bool state);
     281
     282    void setHeightMapEdgeVisibility(const DataSetId& id, bool state);
     283
     284    void setHeightMapEdgeColor(const DataSetId& id, float color[3]);
     285
     286    void setHeightMapEdgeWidth(const DataSetId& id, float edgeWidth);
     287
     288    void setHeightMapContourVisibility(const DataSetId& id, bool state);
     289
     290    void setHeightMapContourEdgeColor(const DataSetId& id, float color[3]);
     291
     292    void setHeightMapContourEdgeWidth(const DataSetId& id, float edgeWidth);
     293
     294    void setHeightMapLighting(const DataSetId& id, bool state);
    209295
    210296    // Meshes
     
    231317
    232318    void setPolyDataLighting(const DataSetId& id, bool state);
     319
     320    // Color-mapped surfaces
     321
     322    void addPseudoColor(const DataSetId& id);
     323
     324    void deletePseudoColor(const DataSetId& id);
     325
     326    PseudoColor *getPseudoColor(const DataSetId& id);
     327
     328    void setPseudoColorColorMap(const DataSetId& id, const ColorMapId& colorMapId);
     329
     330    void setPseudoColorOpacity(const DataSetId& id, double opacity);
     331
     332    void setPseudoColorVisibility(const DataSetId& id, bool state);
     333
     334    void setPseudoColorEdgeVisibility(const DataSetId& id, bool state);
     335
     336    void setPseudoColorEdgeColor(const DataSetId& id, float color[3]);
     337
     338    void setPseudoColorEdgeWidth(const DataSetId& id, float edgeWidth);
     339
     340    void setPseudoColorLighting(const DataSetId& id, bool state);
     341
     342    // Volumes
     343
     344    void addVolume(const DataSetId& id);
     345
     346    void deleteVolume(const DataSetId& id);
     347
     348    Volume *getVolume(const DataSetId& id);
     349
     350    void setVolumeColorMap(const DataSetId& id, const ColorMapId& colorMapId);
     351
     352    void setVolumeOpacity(const DataSetId& id, double opacity);
     353
     354    void setVolumeVisibility(const DataSetId& id, bool state);
     355
     356    void setVolumeAmbient(const DataSetId& id, double coeff);
     357
     358    void setVolumeDiffuse(const DataSetId& id, double coeff);
     359
     360    void setVolumeSpecular(const DataSetId& id, double coeff, double power);
     361
     362    void setVolumeLighting(const DataSetId& id, bool state);
    233363
    234364private:
     
    261391    void initAxes();
    262392    void resetAxes();
     393    void setCameraClippingPlanes();
    263394
    264395    bool _needsRedraw;
     
    279410    ColorMapHashmap _colorMaps;
    280411    DataSetHashmap _dataSets;
     412    Contour2DHashmap _contour2Ds;
     413    Contour3DHashmap _contour3Ds;
     414    GlyphsHashmap _glyphs;
     415    HeightMapHashmap _heightMaps;
     416    PolyDataHashmap _polyDatas;
    281417    PseudoColorHashmap _pseudoColors;
    282     Contour2DHashmap _contours;
    283     PolyDataHashmap _polyDatas;
     418    VolumeHashmap _volumes;
    284419
    285420    CameraMode _cameraMode;
    286421
    287     vtkSmartPointer<vtkPlaneCollection> _clippingPlanes;
     422    vtkSmartPointer<vtkPlane> _clipPlanes[4];
     423    vtkSmartPointer<vtkPlaneCollection> _activeClipPlanes;
    288424    vtkSmartPointer<vtkCubeAxesActor> _cubeAxesActor; // For 3D view
    289425#ifdef USE_CUSTOM_AXES
  • branches/blt4/packages/vizservers/vtkvis/RpVtkRendererCmd.cpp

    r2221 r2302  
    7070    }
    7171    g_renderer->setAxesColor(color);
     72    return TCL_OK;
     73}
     74
     75static int
     76AxisFlyModeOp(ClientData clientData, Tcl_Interp *interp, int objc,
     77              Tcl_Obj *const *objv)
     78{
     79    const char *string = Tcl_GetString(objv[2]);
     80    char c = string[0];
     81    Renderer::AxesFlyMode mode;
     82    if ((c == 's') && (strcmp(string, "static_edges") == 0)) {
     83        mode = Renderer::FLY_STATIC_EDGES;
     84    } else if ((c == 's') && (strcmp(string, "static_triad") == 0)) {
     85        mode = Renderer::FLY_STATIC_TRIAD;
     86    } else if ((c == 'o') && (strcmp(string, "outer_edges") == 0)) {
     87        mode = Renderer::FLY_OUTER_EDGES;
     88    } else if ((c == 'f') && (strcmp(string, "furthest_triad") == 0)) {
     89        mode = Renderer::FLY_FURTHEST_TRIAD;
     90    } else if ((c == 'c') && (strcmp(string, "closest_triad") == 0)) {
     91        mode = Renderer::FLY_CLOSEST_TRIAD;
     92    } else {
     93        Tcl_AppendResult(interp, "bad axis flymode option \"", string,
     94                         "\": should be static_edges, static_triad, outer_edges, furthest_triad, or closest_triad", (char*)NULL);
     95        return TCL_ERROR;
     96    }
     97    g_renderer->setAxesFlyMode(mode);
    7298    return TCL_OK;
    7399}
     
    168194
    169195static Rappture::CmdSpec axisOps[] = {
    170     {"color", 1, AxisColorOp, 5, 5, "r g b"},
    171     {"grid", 1, AxisGridOp, 4, 4, "axis bool"},
    172     {"name", 1, AxisNameOp, 4, 4, "axis title"},
    173     {"units", 1, AxisUnitsOp, 4, 4, "axis units"},
     196    {"color",   1, AxisColorOp, 5, 5, "r g b"},
     197    {"flymode", 1, AxisFlyModeOp, 3, 3, "mode"},
     198    {"grid",    1, AxisGridOp, 4, 4, "axis bool"},
     199    {"name",    1, AxisNameOp, 4, 4, "axis title"},
     200    {"units",   1, AxisUnitsOp, 4, 4, "axis units"},
    174201    {"visible", 1, AxisVisibleOp, 4, 4, "axis bool"}
    175202};
     
    204231    } else {
    205232        Tcl_AppendResult(interp, "bad camera mode option \"", string,
    206                          "\": should be perspective, ortho or image", (char*)NULL);
     233                         "\": should be persp, ortho or image", (char*)NULL);
    207234        return TCL_ERROR;
    208235    }
     
    251278    }
    252279
    253     g_renderer->setSceneOrientation(quat);
     280    g_renderer->setCameraOrientation(quat);
    254281    return TCL_OK;
    255282}
     
    361388
    362389static Rappture::CmdSpec cameraOps[] = {
    363     {"get",    1, CameraGetOrientationOp, 2, 2, ""},
    364     {"mode",   1, CameraModeOp,          3, 3, "mode"},
    365     {"orient", 3, CameraOrientationOp,    6, 6, "qx qy qz qw"},
    366     {"ortho",  3, CameraOrthoOp,          6, 6, "x y width height"},
    367     {"pan",    1, CameraPanOp,            4, 4, "panX panY"},
    368     {"reset",  2, CameraResetOp,          2, 3, "?all?"},
    369     {"rotate", 2, CameraRotateOp,         5, 5, "angle angle angle"},
    370     {"set",    1, CameraSetOp,            11, 11, "posX posY posZ focalPtX focalPtY focalPtZ viewUpX viewUpY viewUpZ"},
    371     {"zoom",   1, CameraZoomOp,          3, 3, "zoomAmount"}
     390    {"get", 1, CameraGetOrientationOp, 2, 2, ""},
     391    {"mode", 1, CameraModeOp, 3, 3, "mode"},
     392    {"orient", 3, CameraOrientationOp, 6, 6, "qw qx qy qz"},
     393    {"ortho", 1, CameraOrthoOp, 6, 6, "x y width height"},
     394    {"pan", 1, CameraPanOp, 4, 4, "panX panY"},
     395    {"reset", 2, CameraResetOp, 2, 3, "?all?"},
     396    {"rotate", 2, CameraRotateOp, 5, 5, "angle angle angle"},
     397    {"set", 1, CameraSetOp, 11, 11, "posX posY posZ focalPtX focalPtY focalPtZ viewUpX viewUpY viewUpZ"},
     398    {"zoom", 1, CameraZoomOp, 3, 3, "zoomAmount"}
    372399};
    373400static int nCameraOps = NumCmdSpecs(cameraOps);
     
    481508
    482509static Rappture::CmdSpec colorMapOps[] = {
    483     {"add", 1, ColorMapAddOp, 5, 5, "colorMapName colormap alphamap"},
    484     {"delete", 1, ColorMapDeleteOp, 2, 3, "?colorMapName?"}
     510    { "add",    1, ColorMapAddOp,    5, 5, "colorMapName colormap alphamap"},
     511    { "delete", 1, ColorMapDeleteOp, 2, 3, "?colorMapName?"}
    485512};
    486513static int nColorMapOps = NumCmdSpecs(colorMapOps);
     
    524551        const char *name = Tcl_GetString(objv[4]);
    525552        g_renderer->addContour2D(name);
    526         g_renderer->setContourList(name, contourList);
     553        g_renderer->setContour2DContourList(name, contourList);
    527554    } else {
    528555        g_renderer->addContour2D("all");
    529         g_renderer->setContourList("all", contourList);
     556        g_renderer->setContour2DContourList("all", contourList);
    530557    }
    531558    return TCL_OK;
     
    543570        const char *name = Tcl_GetString(objv[4]);
    544571        g_renderer->addContour2D(name);
    545         g_renderer->setContours(name, numContours);
     572        g_renderer->setContour2DContours(name, numContours);
    546573    } else {
    547574        g_renderer->addContour2D("all");
    548         g_renderer->setContours("all", numContours);
     575        g_renderer->setContour2DContours("all", numContours);
    549576    }
    550577    return TCL_OK;
     
    594621    if (objc == 4) {
    595622        const char *name = Tcl_GetString(objv[3]);
    596         g_renderer->setContourLighting(name, state);
    597     } else {
    598         g_renderer->setContourLighting("all", state);
     623        g_renderer->setContour2DLighting(name, state);
     624    } else {
     625        g_renderer->setContour2DLighting("all", state);
    599626    }
    600627    return TCL_OK;
     
    613640    if (objc == 6) {
    614641        const char *name = Tcl_GetString(objv[5]);
    615         g_renderer->setContourEdgeColor(name, color);
    616     } else {
    617         g_renderer->setContourEdgeColor("all", color);
     642        g_renderer->setContour2DEdgeColor(name, color);
     643    } else {
     644        g_renderer->setContour2DEdgeColor("all", color);
    618645    }
    619646    return TCL_OK;
     
    630657    if (objc == 4) {
    631658        const char *name = Tcl_GetString(objv[3]);
    632         g_renderer->setContourEdgeWidth(name, width);
    633     } else {
    634         g_renderer->setContourEdgeWidth("all", width);
     659        g_renderer->setContour2DEdgeWidth(name, width);
     660    } else {
     661        g_renderer->setContour2DEdgeWidth("all", width);
    635662    }
    636663    return TCL_OK;
     
    647674    if (objc == 4) {
    648675        const char *name = Tcl_GetString(objv[3]);
    649         g_renderer->setContourOpacity(name, opacity);
    650     } else {
    651         g_renderer->setContourOpacity("all", opacity);
     676        g_renderer->setContour2DOpacity(name, opacity);
     677    } else {
     678        g_renderer->setContour2DOpacity("all", opacity);
    652679    }
    653680    return TCL_OK;
     
    664691    if (objc == 4) {
    665692        const char *name = Tcl_GetString(objv[3]);
    666         g_renderer->setContourVisibility(name, state);
    667     } else {
    668         g_renderer->setContourVisibility("all", state);
     693        g_renderer->setContour2DVisibility(name, state);
     694    } else {
     695        g_renderer->setContour2DVisibility("all", state);
    669696    }
    670697    return TCL_OK;
     
    672699
    673700static Rappture::CmdSpec contour2dOps[] = {
    674     {"add", 1, Contour2DAddOp, 4, 5, "oper value ?dataSetName?"},
    675     {"delete", 1, Contour2DDeleteOp, 2, 3, "?dataSetName?"},
    676     {"lighting", 3, Contour2DLightingOp, 3, 4, "bool ?dataSetName?"},
     701    {"add",       1, Contour2DAddOp, 4, 5, "oper value ?dataSetName?"},
     702    {"delete",    1, Contour2DDeleteOp, 2, 3, "?dataSetName?"},
     703    {"lighting",  3, Contour2DLightingOp, 3, 4, "bool ?dataSetName?"},
    677704    {"linecolor", 5, Contour2DLineColorOp, 5, 6, "r g b ?dataSetName?"},
    678705    {"linewidth", 5, Contour2DLineWidthOp, 3, 4, "width ?dataSetName?"},
    679     {"opacity", 1, Contour2DOpacityOp, 3, 4, "value ?dataSetName?"},
    680     {"visible", 1, Contour2DVisibleOp, 3, 4, "bool ?dataSetName?"}
     706    {"opacity",   1, Contour2DOpacityOp, 3, 4, "value ?dataSetName?"},
     707    {"visible",   1, Contour2DVisibleOp, 3, 4, "bool ?dataSetName?"}
    681708};
    682709static int nContour2dOps = NumCmdSpecs(contour2dOps);
     
    689716
    690717    proc = Rappture::GetOpFromObj(interp, nContour2dOps, contour2dOps,
     718                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
     719    if (proc == NULL) {
     720        return TCL_ERROR;
     721    }
     722    return (*proc) (clientData, interp, objc, objv);
     723}
     724
     725static int
     726Contour3DAddContourListOp(ClientData clientData, Tcl_Interp *interp, int objc,
     727                          Tcl_Obj *const *objv)
     728{
     729    std::vector<double> contourList;
     730
     731    int clistc;
     732    Tcl_Obj **clistv;
     733
     734    if (Tcl_ListObjGetElements(interp, objv[3], &clistc, &clistv) != TCL_OK) {
     735        return TCL_ERROR;
     736    }
     737
     738    for (int i = 0; i < clistc; i++) {
     739        double val;
     740        if (Tcl_GetDoubleFromObj(interp, clistv[i], &val) != TCL_OK) {
     741            return TCL_ERROR;
     742        }
     743        contourList.push_back(val);
     744    }
     745
     746    if (objc == 5) {
     747        const char *name = Tcl_GetString(objv[4]);
     748        g_renderer->addContour3D(name);
     749        g_renderer->setContour3DContourList(name, contourList);
     750    } else {
     751        g_renderer->addContour3D("all");
     752        g_renderer->setContour3DContourList("all", contourList);
     753    }
     754    return TCL_OK;
     755}
     756
     757static int
     758Contour3DAddNumContoursOp(ClientData clientData, Tcl_Interp *interp, int objc,
     759                          Tcl_Obj *const *objv)
     760{
     761    int numContours;
     762    if (Tcl_GetIntFromObj(interp, objv[3], &numContours) != TCL_OK) {
     763        return TCL_ERROR;
     764    }
     765    if (objc == 5) {
     766        const char *name = Tcl_GetString(objv[4]);
     767        g_renderer->addContour3D(name);
     768        g_renderer->setContour3DContours(name, numContours);
     769    } else {
     770        g_renderer->addContour3D("all");
     771        g_renderer->setContour3DContours("all", numContours);
     772    }
     773    return TCL_OK;
     774}
     775
     776static Rappture::CmdSpec contour3dAddOps[] = {
     777    {"contourlist", 1, Contour3DAddContourListOp, 4, 5, "contourList ?dataSetName?"},
     778    {"numcontours", 1, Contour3DAddNumContoursOp, 4, 5, "numContours ?dataSetName?"}
     779};
     780static int nContour3dAddOps = NumCmdSpecs(contour3dAddOps);
     781
     782static int
     783Contour3DAddOp(ClientData clientData, Tcl_Interp *interp, int objc,
     784               Tcl_Obj *const *objv)
     785{
     786    Tcl_ObjCmdProc *proc;
     787
     788    proc = Rappture::GetOpFromObj(interp, nContour3dAddOps, contour3dAddOps,
     789                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
     790    if (proc == NULL) {
     791        return TCL_ERROR;
     792    }
     793    return (*proc) (clientData, interp, objc, objv);
     794}
     795
     796static int
     797Contour3DColorOp(ClientData clientData, Tcl_Interp *interp, int objc,
     798                 Tcl_Obj *const *objv)
     799{
     800    float color[3];
     801    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
     802        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
     803        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
     804        return TCL_ERROR;
     805    }
     806    if (objc == 6) {
     807        const char *name = Tcl_GetString(objv[5]);
     808        g_renderer->setContour3DColor(name, color);
     809    } else {
     810        g_renderer->setContour3DColor("all", color);
     811    }
     812    return TCL_OK;
     813}
     814
     815static int
     816Contour3DColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc,
     817                    Tcl_Obj *const *objv)
     818{
     819    const char *colorMapName = Tcl_GetString(objv[2]);
     820    if (objc == 4) {
     821        const char *dataSetName = Tcl_GetString(objv[3]);
     822        g_renderer->setContour3DColorMap(dataSetName, colorMapName);
     823    } else {
     824        g_renderer->setContour3DColorMap("all", colorMapName);
     825    }
     826    return TCL_OK;
     827}
     828
     829static int
     830Contour3DDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc,
     831                  Tcl_Obj *const *objv)
     832{
     833    if (objc == 3) {
     834        const char *name = Tcl_GetString(objv[2]);
     835        g_renderer->deleteContour3D(name);
     836    } else {
     837        g_renderer->deleteContour3D("all");
     838    }
     839    return TCL_OK;
     840}
     841
     842static int
     843Contour3DEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc,
     844                          Tcl_Obj *const *objv)
     845{
     846    bool state;
     847    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
     848        return TCL_ERROR;
     849    }
     850    if (objc == 4) {
     851        const char *name = Tcl_GetString(objv[3]);
     852        g_renderer->setContour3DEdgeVisibility(name, state);
     853    } else {
     854        g_renderer->setContour3DEdgeVisibility("all", state);
     855    }
     856    return TCL_OK;
     857}
     858
     859static int
     860Contour3DLightingOp(ClientData clientData, Tcl_Interp *interp, int objc,
     861                    Tcl_Obj *const *objv)
     862{
     863    bool state;
     864    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
     865        return TCL_ERROR;
     866    }
     867    if (objc == 4) {
     868        const char *name = Tcl_GetString(objv[3]);
     869        g_renderer->setContour3DLighting(name, state);
     870    } else {
     871        g_renderer->setContour3DLighting("all", state);
     872    }
     873    return TCL_OK;
     874}
     875
     876static int
     877Contour3DLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc,
     878                     Tcl_Obj *const *objv)
     879{
     880    float color[3];
     881    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
     882        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
     883        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
     884        return TCL_ERROR;
     885    }
     886    if (objc == 6) {
     887        const char *name = Tcl_GetString(objv[5]);
     888        g_renderer->setContour3DEdgeColor(name, color);
     889    } else {
     890        g_renderer->setContour3DEdgeColor("all", color);
     891    }
     892    return TCL_OK;
     893}
     894
     895static int
     896Contour3DLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc,
     897                     Tcl_Obj *const *objv)
     898{
     899    float width;
     900    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
     901        return TCL_ERROR;
     902    }
     903    if (objc == 4) {
     904        const char *name = Tcl_GetString(objv[3]);
     905        g_renderer->setContour3DEdgeWidth(name, width);
     906    } else {
     907        g_renderer->setContour3DEdgeWidth("all", width);
     908    }
     909    return TCL_OK;
     910}
     911
     912static int
     913Contour3DOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc,
     914                   Tcl_Obj *const *objv)
     915{
     916    double opacity;
     917    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
     918        return TCL_ERROR;
     919    }
     920    if (objc == 4) {
     921        const char *name = Tcl_GetString(objv[3]);
     922        g_renderer->setContour3DOpacity(name, opacity);
     923    } else {
     924        g_renderer->setContour3DOpacity("all", opacity);
     925    }
     926    return TCL_OK;
     927}
     928
     929static int
     930Contour3DVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc,
     931                   Tcl_Obj *const *objv)
     932{
     933    bool state;
     934    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
     935        return TCL_ERROR;
     936    }
     937    if (objc == 4) {
     938        const char *name = Tcl_GetString(objv[3]);
     939        g_renderer->setContour3DVisibility(name, state);
     940    } else {
     941        g_renderer->setContour3DVisibility("all", state);
     942    }
     943    return TCL_OK;
     944}
     945
     946static int
     947Contour3DWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc,
     948                     Tcl_Obj *const *objv)
     949{
     950    bool state;
     951    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
     952        return TCL_ERROR;
     953    }
     954    if (objc == 4) {
     955        const char *name = Tcl_GetString(objv[3]);
     956        g_renderer->setContour3DWireframe(name, state);
     957    } else {
     958        g_renderer->setContour3DWireframe("all", state);
     959    }
     960    return TCL_OK;
     961}
     962
     963static Rappture::CmdSpec contour3dOps[] = {
     964    {"add",       1, Contour3DAddOp, 4, 5, "oper value ?dataSetName?"},
     965    {"color",     6, Contour3DColorOp, 5, 6, "r g b ?dataSetName?"},
     966    {"colormap",  6, Contour3DColorMapOp, 3, 4, "colorMapName ?dataSetName?"},
     967    {"delete",    1, Contour3DDeleteOp, 2, 3, "?dataSetName?"},
     968    {"edges",     1, Contour3DEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
     969    {"lighting",  3, Contour3DLightingOp, 3, 4, "bool ?dataSetName?"},
     970    {"linecolor", 5, Contour3DLineColorOp, 5, 6, "r g b ?dataSetName?"},
     971    {"linewidth", 5, Contour3DLineWidthOp, 3, 4, "width ?dataSetName?"},
     972    {"opacity",   1, Contour3DOpacityOp, 3, 4, "value ?dataSetName?"},
     973    {"visible",   1, Contour3DVisibleOp, 3, 4, "bool ?dataSetName?"},
     974    {"wireframe", 1, Contour3DWireframeOp, 3, 4, "bool ?dataSetName?"}
     975};
     976static int nContour3dOps = NumCmdSpecs(contour3dOps);
     977
     978static int
     979Contour3DCmd(ClientData clientData, Tcl_Interp *interp, int objc,
     980             Tcl_Obj *const *objv)
     981{
     982    Tcl_ObjCmdProc *proc;
     983
     984    proc = Rappture::GetOpFromObj(interp, nContour3dOps, contour3dOps,
    691985                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
    692986    if (proc == NULL) {
     
    7311025    TRACE("bytesRead: %d", ofs);
    7321026    if (bytesRead < 0) {
     1027        free(data);
    7331028        return TCL_ERROR;
    7341029    }
     
    7371032    TRACE("bytesRead: %d '%c'", bytesRead, data[0]);
    7381033    if (bytesRead < (size_t)nbytes) {
     1034        free(data);
    7391035        return TCL_ERROR;
    7401036    }
     
    8871183
    8881184static Rappture::CmdSpec dataSetOps[] = {
    889     {"add", 1, DataSetAddOp, 6, 6, "name data follows nBytes"},
    890     {"delete", 1, DataSetDeleteOp, 2, 3, "?name?"},
     1185    {"add",      1, DataSetAddOp, 6, 6, "name data follows nBytes"},
     1186    {"delete",   1, DataSetDeleteOp, 2, 3, "?name?"},
    8911187    {"getvalue", 1, DataSetGetValueOp, 6, 7, "oper x y ?z? name"},
    8921188    {"maprange", 1, DataSetMapRangeOp, 3, 3, "value"},
    893     {"opacity", 1, DataSetOpacityOp, 3, 4, "value ?name?"},
    894     {"visible", 1, DataSetVisibleOp, 3, 4, "bool ?name?"}
     1189    {"opacity",  1, DataSetOpacityOp, 3, 4, "value ?name?"},
     1190    {"visible",  1, DataSetVisibleOp, 3, 4, "bool ?name?"}
    8951191};
    8961192static int nDataSetOps = NumCmdSpecs(dataSetOps);
     
    9031199
    9041200    proc = Rappture::GetOpFromObj(interp, nDataSetOps, dataSetOps,
     1201                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
     1202    if (proc == NULL) {
     1203        return TCL_ERROR;
     1204    }
     1205    return (*proc) (clientData, interp, objc, objv);
     1206}
     1207
     1208static int
     1209GlyphsAddOp(ClientData clientData, Tcl_Interp *interp, int objc,
     1210            Tcl_Obj *const *objv)
     1211{
     1212    Glyphs::GlyphShape shape;
     1213
     1214    const char *shapeOpt = Tcl_GetString(objv[2]);
     1215    if (shapeOpt[0] == 'a' && strcmp(shapeOpt, "arrow") == 0) {
     1216        shape = Glyphs::ARROW;
     1217    } else if (shapeOpt[0] == 'c' && strcmp(shapeOpt, "cone") == 0) {
     1218        shape = Glyphs::CONE;
     1219    } else if (shapeOpt[0] == 'c' && strcmp(shapeOpt, "cube") == 0) {
     1220        shape = Glyphs::CUBE;
     1221    } else if (shapeOpt[0] == 'c' && strcmp(shapeOpt, "cylinder") == 0) {
     1222        shape = Glyphs::CYLINDER;
     1223    } else if (shapeOpt[0] == 'd' && strcmp(shapeOpt, "dodecahedron") == 0) {
     1224        shape = Glyphs::DODECAHEDRON;
     1225    } else if (shapeOpt[0] == 'i' && strcmp(shapeOpt, "icosahedron") == 0) {
     1226        shape = Glyphs::ICOSAHEDRON;
     1227    } else if (shapeOpt[0] == 'o' && strcmp(shapeOpt, "octahedron") == 0) {
     1228        shape = Glyphs::OCTAHEDRON;
     1229    } else if (shapeOpt[0] == 's' && strcmp(shapeOpt, "sphere") == 0) {
     1230        shape = Glyphs::SPHERE;
     1231    } else if (shapeOpt[0] == 't' && strcmp(shapeOpt, "tetrahedron") == 0) {
     1232        shape = Glyphs::TETRAHEDRON;
     1233    } else {
     1234        Tcl_AppendResult(interp, "bad shape option \"", shapeOpt,
     1235                         "\": should be one of: 'arrow', 'cone', 'cube', 'cylinder', 'dodecahedron', 'icosahedron', 'octahedron', 'sphere', 'tetrahedron'", (char*)NULL);
     1236        return TCL_ERROR;
     1237    }
     1238
     1239    if (objc == 4) {
     1240        const char *name = Tcl_GetString(objv[3]);
     1241        g_renderer->addGlyphs(name);
     1242        g_renderer->setGlyphsShape(name, shape);
     1243    } else {
     1244        g_renderer->addGlyphs("all");
     1245        g_renderer->setGlyphsShape("all", shape);
     1246    }
     1247    return TCL_OK;
     1248}
     1249
     1250static int
     1251GlyphsColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc,
     1252                 Tcl_Obj *const *objv)
     1253{
     1254    const char *colorMapName = Tcl_GetString(objv[2]);
     1255    if (objc == 4) {
     1256        const char *dataSetName = Tcl_GetString(objv[3]);
     1257        g_renderer->setGlyphsColorMap(dataSetName, colorMapName);
     1258    } else {
     1259        g_renderer->setGlyphsColorMap("all", colorMapName);
     1260    }
     1261    return TCL_OK;
     1262}
     1263
     1264static int
     1265GlyphsDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc,
     1266               Tcl_Obj *const *objv)
     1267{
     1268    if (objc == 3) {
     1269        const char *name = Tcl_GetString(objv[2]);
     1270        g_renderer->deleteGlyphs(name);
     1271    } else {
     1272        g_renderer->deleteGlyphs("all");
     1273    }
     1274    return TCL_OK;
     1275}
     1276
     1277static int
     1278GlyphsLightingOp(ClientData clientData, Tcl_Interp *interp, int objc,
     1279                 Tcl_Obj *const *objv)
     1280{
     1281    bool state;
     1282    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
     1283        return TCL_ERROR;
     1284    }
     1285    if (objc == 4) {
     1286        const char *name = Tcl_GetString(objv[3]);
     1287        g_renderer->setGlyphsLighting(name, state);
     1288    } else {
     1289        g_renderer->setGlyphsLighting("all", state);
     1290    }
     1291    return TCL_OK;
     1292}
     1293
     1294static int
     1295GlyphsOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc,
     1296                Tcl_Obj *const *objv)
     1297{
     1298    double opacity;
     1299    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
     1300        return TCL_ERROR;
     1301    }
     1302    if (objc == 4) {
     1303        const char *name = Tcl_GetString(objv[3]);
     1304        g_renderer->setGlyphsOpacity(name, opacity);
     1305    } else {
     1306        g_renderer->setGlyphsOpacity("all", opacity);
     1307    }
     1308    return TCL_OK;
     1309}
     1310
     1311static int
     1312GlyphsScaleOp(ClientData clientData, Tcl_Interp *interp, int objc,
     1313              Tcl_Obj *const *objv)
     1314{
     1315    double scale;
     1316    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale) != TCL_OK) {
     1317        return TCL_ERROR;
     1318    }
     1319    if (objc == 4) {
     1320        const char *name = Tcl_GetString(objv[3]);
     1321        g_renderer->setGlyphsScaleFactor(name, scale);
     1322    } else {
     1323        g_renderer->setGlyphsScaleFactor("all", scale);
     1324    }
     1325    return TCL_OK;
     1326}
     1327
     1328static int
     1329GlyphsShapeOp(ClientData clientData, Tcl_Interp *interp, int objc,
     1330              Tcl_Obj *const *objv)
     1331{
     1332    Glyphs::GlyphShape shape;
     1333
     1334    const char *shapeOpt = Tcl_GetString(objv[2]);
     1335    if (shapeOpt[0] == 'a' && strcmp(shapeOpt, "arrow") == 0) {
     1336        shape = Glyphs::ARROW;
     1337    } else if (shapeOpt[0] == 'c' && strcmp(shapeOpt, "cone") == 0) {
     1338        shape = Glyphs::CONE;
     1339    } else if (shapeOpt[0] == 'c' && strcmp(shapeOpt, "cube") == 0) {
     1340        shape = Glyphs::CUBE;
     1341    } else if (shapeOpt[0] == 'c' && strcmp(shapeOpt, "cylinder") == 0) {
     1342        shape = Glyphs::CYLINDER;
     1343    } else if (shapeOpt[0] == 'd' && strcmp(shapeOpt, "dodecahedron") == 0) {
     1344        shape = Glyphs::DODECAHEDRON;
     1345    } else if (shapeOpt[0] == 'i' && strcmp(shapeOpt, "icosahedron") == 0) {
     1346        shape = Glyphs::ICOSAHEDRON;
     1347    } else if (shapeOpt[0] == 'o' && strcmp(shapeOpt, "octahedron") == 0) {
     1348        shape = Glyphs::OCTAHEDRON;
     1349    } else if (shapeOpt[0] == 's' && strcmp(shapeOpt, "sphere") == 0) {
     1350        shape = Glyphs::SPHERE;
     1351    } else if (shapeOpt[0] == 't' && strcmp(shapeOpt, "tetrahedron") == 0) {
     1352        shape = Glyphs::TETRAHEDRON;
     1353    } else {
     1354        Tcl_AppendResult(interp, "bad shape option \"", shapeOpt,
     1355                         "\": should be one of: 'arrow', 'cone', 'cube', 'cylinder', 'dodecahedron', 'icosahedron', 'octahedron', 'sphere', 'tetrahedron'", (char*)NULL);
     1356        return TCL_ERROR;
     1357    }
     1358
     1359    if (objc == 4) {
     1360        const char *name = Tcl_GetString(objv[3]);
     1361        g_renderer->setGlyphsShape(name, shape);
     1362    } else {
     1363        g_renderer->setGlyphsShape("all", shape);
     1364    }
     1365    return TCL_OK;
     1366}
     1367
     1368static int
     1369GlyphsVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc,
     1370                Tcl_Obj *const *objv)
     1371{
     1372    bool state;
     1373    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
     1374        return TCL_ERROR;
     1375    }
     1376    if (objc == 4) {
     1377        const char *name = Tcl_GetString(objv[3]);
     1378        g_renderer->setGlyphsVisibility(name, state);
     1379    } else {
     1380        g_renderer->setGlyphsVisibility("all", state);
     1381    }
     1382    return TCL_OK;
     1383}
     1384
     1385static Rappture::CmdSpec glyphsOps[] = {
     1386    {"add",      1, GlyphsAddOp, 3, 4, "shape ?dataSetNme?"},
     1387    {"colormap", 1, GlyphsColorMapOp, 3, 4, "colorMapName ?dataSetNme?"},
     1388    {"delete",   1, GlyphsDeleteOp, 2, 3, "?dataSetName?"},
     1389    {"lighting", 1, GlyphsLightingOp, 3, 4, "bool ?dataSetName?"},
     1390    {"opacity",  1, GlyphsOpacityOp, 3, 4, "value ?dataSetName?"},
     1391    {"scale",    2, GlyphsScaleOp, 3, 4, "scaleFactor ?dataSetName?"},
     1392    {"shape",    2, GlyphsShapeOp, 3, 4, "shapeVal ?dataSetName?"},
     1393    {"visible",  1, GlyphsVisibleOp, 3, 4, "bool ?dataSetName?"}
     1394};
     1395static int nGlyphsOps = NumCmdSpecs(glyphsOps);
     1396
     1397static int
     1398GlyphsCmd(ClientData clientData, Tcl_Interp *interp, int objc,
     1399          Tcl_Obj *const *objv)
     1400{
     1401    Tcl_ObjCmdProc *proc;
     1402
     1403    proc = Rappture::GetOpFromObj(interp, nGlyphsOps, glyphsOps,
     1404                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
     1405    if (proc == NULL) {
     1406        return TCL_ERROR;
     1407    }
     1408    return (*proc) (clientData, interp, objc, objv);
     1409}
     1410
     1411static int
     1412HeightMapAddContourListOp(ClientData clientData, Tcl_Interp *interp, int objc,
     1413                          Tcl_Obj *const *objv)
     1414{
     1415    std::vector<double> contourList;
     1416
     1417    int clistc;
     1418    Tcl_Obj **clistv;
     1419
     1420    if (Tcl_ListObjGetElements(interp, objv[3], &clistc, &clistv) != TCL_OK) {
     1421        return TCL_ERROR;
     1422    }
     1423
     1424    for (int i = 0; i < clistc; i++) {
     1425        double val;
     1426        if (Tcl_GetDoubleFromObj(interp, clistv[i], &val) != TCL_OK) {
     1427            return TCL_ERROR;
     1428        }
     1429        contourList.push_back(val);
     1430    }
     1431
     1432    if (objc == 5) {
     1433        const char *name = Tcl_GetString(objv[4]);
     1434        g_renderer->addHeightMap(name);
     1435        g_renderer->setHeightMapContourList(name, contourList);
     1436    } else {
     1437        g_renderer->addHeightMap("all");
     1438        g_renderer->setHeightMapContourList("all", contourList);
     1439    }
     1440    return TCL_OK;
     1441}
     1442
     1443static int
     1444HeightMapAddNumContoursOp(ClientData clientData, Tcl_Interp *interp, int objc,
     1445                          Tcl_Obj *const *objv)
     1446{
     1447    int numContours;
     1448    if (Tcl_GetIntFromObj(interp, objv[3], &numContours) != TCL_OK) {
     1449        return TCL_ERROR;
     1450    }
     1451    if (objc == 5) {
     1452        const char *name = Tcl_GetString(objv[4]);
     1453        g_renderer->addHeightMap(name);
     1454        g_renderer->setHeightMapContours(name, numContours);
     1455    } else {
     1456        g_renderer->addHeightMap("all");
     1457        g_renderer->setHeightMapContours("all", numContours);
     1458    }
     1459    return TCL_OK;
     1460}
     1461
     1462static Rappture::CmdSpec heightmapAddOps[] = {
     1463    {"contourlist", 1, HeightMapAddContourListOp, 4, 5, "contourList ?dataSetName?"},
     1464    {"numcontours", 1, HeightMapAddNumContoursOp, 4, 5, "numContours ?dataSetName?"}
     1465};
     1466static int nHeightmapAddOps = NumCmdSpecs(heightmapAddOps);
     1467
     1468static int
     1469HeightMapAddOp(ClientData clientData, Tcl_Interp *interp, int objc,
     1470               Tcl_Obj *const *objv)
     1471{
     1472    Tcl_ObjCmdProc *proc;
     1473
     1474    proc = Rappture::GetOpFromObj(interp, nHeightmapAddOps, heightmapAddOps,
     1475                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
     1476    if (proc == NULL) {
     1477        return TCL_ERROR;
     1478    }
     1479    return (*proc) (clientData, interp, objc, objv);
     1480}
     1481
     1482static int
     1483HeightMapColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc,
     1484                    Tcl_Obj *const *objv)
     1485{
     1486    const char *colorMapName = Tcl_GetString(objv[2]);
     1487    if (objc == 4) {
     1488        const char *dataSetName = Tcl_GetString(objv[3]);
     1489        g_renderer->setHeightMapColorMap(dataSetName, colorMapName);
     1490    } else {
     1491        g_renderer->setHeightMapColorMap("all", colorMapName);
     1492    }
     1493    return TCL_OK;
     1494}
     1495
     1496static int
     1497HeightMapContourLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc,
     1498                            Tcl_Obj *const *objv)
     1499{
     1500    float color[3];
     1501    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
     1502        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
     1503        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
     1504        return TCL_ERROR;
     1505    }
     1506    if (objc == 6) {
     1507        const char *name = Tcl_GetString(objv[5]);
     1508        g_renderer->setHeightMapContourEdgeColor(name, color);
     1509    } else {
     1510        g_renderer->setHeightMapContourEdgeColor("all", color);
     1511    }
     1512    return TCL_OK;
     1513}
     1514
     1515static int
     1516HeightMapContourLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc,
     1517                            Tcl_Obj *const *objv)
     1518{
     1519    float width;
     1520    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
     1521        return TCL_ERROR;
     1522    }
     1523    if (objc == 4) {
     1524        const char *name = Tcl_GetString(objv[3]);
     1525        g_renderer->setHeightMapContourEdgeWidth(name, width);
     1526    } else {
     1527        g_renderer->setHeightMapContourEdgeWidth("all", width);
     1528    }
     1529    return TCL_OK;
     1530}
     1531
     1532static int
     1533HeightMapContourVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc,
     1534                          Tcl_Obj *const *objv)
     1535{
     1536    bool state;
     1537    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
     1538        return TCL_ERROR;
     1539    }
     1540    if (objc == 4) {
     1541        const char *name = Tcl_GetString(objv[3]);
     1542        g_renderer->setHeightMapContourVisibility(name, state);
     1543    } else {
     1544        g_renderer->setHeightMapContourVisibility("all", state);
     1545    }
     1546    return TCL_OK;
     1547}
     1548
     1549static int
     1550HeightMapDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc,
     1551                  Tcl_Obj *const *objv)
     1552{
     1553    if (objc == 3) {
     1554        const char *name = Tcl_GetString(objv[2]);
     1555        g_renderer->deleteHeightMap(name);
     1556    } else {
     1557        g_renderer->deleteHeightMap("all");
     1558    }
     1559    return TCL_OK;
     1560}
     1561
     1562static int
     1563HeightMapEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc,
     1564                          Tcl_Obj *const *objv)
     1565{
     1566    bool state;
     1567    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
     1568        return TCL_ERROR;
     1569    }
     1570    if (objc == 4) {
     1571        const char *name = Tcl_GetString(objv[3]);
     1572        g_renderer->setHeightMapEdgeVisibility(name, state);
     1573    } else {
     1574        g_renderer->setHeightMapEdgeVisibility("all", state);
     1575    }
     1576    return TCL_OK;
     1577}
     1578
     1579static int
     1580HeightMapHeightScaleOp(ClientData clientData, Tcl_Interp *interp, int objc,
     1581                       Tcl_Obj *const *objv)
     1582{
     1583    double scale;
     1584    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale) != TCL_OK) {
     1585        return TCL_ERROR;
     1586    }
     1587    if (objc == 4) {
     1588        const char *name = Tcl_GetString(objv[3]);
     1589        g_renderer->setHeightMapHeightScale(name, scale);
     1590    } else {
     1591        g_renderer->setHeightMapHeightScale("all", scale);
     1592    }
     1593    return TCL_OK;
     1594}
     1595
     1596static int
     1597HeightMapLightingOp(ClientData clientData, Tcl_Interp *interp, int objc,
     1598                    Tcl_Obj *const *objv)
     1599{
     1600    bool state;
     1601    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
     1602        return TCL_ERROR;
     1603    }
     1604    if (objc == 4) {
     1605        const char *name = Tcl_GetString(objv[3]);
     1606        g_renderer->setHeightMapLighting(name, state);
     1607    } else {
     1608        g_renderer->setHeightMapLighting("all", state);
     1609    }
     1610    return TCL_OK;
     1611}
     1612
     1613static int
     1614HeightMapLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc,
     1615                     Tcl_Obj *const *objv)
     1616{
     1617    float color[3];
     1618    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
     1619        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
     1620        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
     1621        return TCL_ERROR;
     1622    }
     1623    if (objc == 6) {
     1624        const char *name = Tcl_GetString(objv[5]);
     1625        g_renderer->setHeightMapEdgeColor(name, color);
     1626    } else {
     1627        g_renderer->setHeightMapEdgeColor("all", color);
     1628    }
     1629    return TCL_OK;
     1630}
     1631
     1632static int
     1633HeightMapLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc,
     1634                     Tcl_Obj *const *objv)
     1635{
     1636    float width;
     1637    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
     1638        return TCL_ERROR;
     1639    }
     1640    if (objc == 4) {
     1641        const char *name = Tcl_GetString(objv[3]);
     1642        g_renderer->setHeightMapEdgeWidth(name, width);
     1643    } else {
     1644        g_renderer->setHeightMapEdgeWidth("all", width);
     1645    }
     1646    return TCL_OK;
     1647}
     1648
     1649static int
     1650HeightMapOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc,
     1651                   Tcl_Obj *const *objv)
     1652{
     1653    double opacity;
     1654    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
     1655        return TCL_ERROR;
     1656    }
     1657    if (objc == 4) {
     1658        const char *name = Tcl_GetString(objv[3]);
     1659        g_renderer->setHeightMapOpacity(name, opacity);
     1660    } else {
     1661        g_renderer->setHeightMapOpacity("all", opacity);
     1662    }
     1663    return TCL_OK;
     1664}
     1665
     1666static int
     1667HeightMapVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc,
     1668                   Tcl_Obj *const *objv)
     1669{
     1670    bool state;
     1671    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
     1672        return TCL_ERROR;
     1673    }
     1674    if (objc == 4) {
     1675        const char *name = Tcl_GetString(objv[3]);
     1676        g_renderer->setHeightMapVisibility(name, state);
     1677    } else {
     1678        g_renderer->setHeightMapVisibility("all", state);
     1679    }
     1680    return TCL_OK;
     1681}
     1682
     1683static int
     1684HeightMapVolumeSliceOp(ClientData clientData, Tcl_Interp *interp, int objc,
     1685                       Tcl_Obj *const *objv)
     1686{
     1687    double ratio;
     1688    if (Tcl_GetDoubleFromObj(interp, objv[3], &ratio) != TCL_OK) {
     1689        return TCL_ERROR;
     1690    }
     1691    const char *string = Tcl_GetString(objv[2]);
     1692    char c = string[0];
     1693    HeightMap::Axis axis;
     1694    if ((c == 'x') && (strcmp(string, "x") == 0)) {
     1695        axis = HeightMap::X_AXIS;
     1696    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
     1697        axis = HeightMap::Y_AXIS;
     1698    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
     1699        axis = HeightMap::Z_AXIS;
     1700    } else {
     1701        Tcl_AppendResult(interp, "bad axis option \"", string,
     1702                         "\": should be axisName ratio", (char*)NULL);
     1703        return TCL_ERROR;
     1704    }
     1705    if (objc == 5) {
     1706        const char *name = Tcl_GetString(objv[4]);
     1707        g_renderer->setHeightMapVolumeSlice(name, axis, ratio);
     1708    } else {
     1709        g_renderer->setHeightMapVolumeSlice("all", axis, ratio);
     1710    }
     1711    return TCL_OK;
     1712}
     1713
     1714static Rappture::CmdSpec heightmapOps[] = {
     1715    {"add",          1, HeightMapAddOp, 4, 5, "oper value ?dataSetName?"},
     1716    {"colormap",     1, HeightMapColorMapOp, 3, 4, "colorMapName ?dataSetName?"},
     1717    {"delete",       1, HeightMapDeleteOp, 2, 3, "?dataSetName?"},
     1718    {"edges",        1, HeightMapEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
     1719    {"heightscale",  1, HeightMapHeightScaleOp, 3, 4, "value ?dataSetName?"},
     1720    {"isolinecolor", 8, HeightMapContourLineColorOp, 5, 6, "r g b ?dataSetName?"},
     1721    {"isolines",     8, HeightMapContourVisibleOp, 3, 4, "bool ?dataSetName?"},
     1722    {"isolinewidth", 8, HeightMapContourLineWidthOp, 3, 4, "width ?dataSetName?"},
     1723    {"lighting",     3, HeightMapLightingOp, 3, 4, "bool ?dataSetName?"},
     1724    {"linecolor",    5, HeightMapLineColorOp, 5, 6, "r g b ?dataSetName?"},
     1725    {"linewidth",    5, HeightMapLineWidthOp, 3, 4, "width ?dataSetName?"},
     1726    {"opacity",      1, HeightMapOpacityOp, 3, 4, "value ?dataSetName?"},
     1727    {"visible",      2, HeightMapVisibleOp, 3, 4, "bool ?dataSetName?"},
     1728    {"volumeslice",  2, HeightMapVolumeSliceOp, 4, 5, "axis ratio ?dataSetName?"}
     1729};
     1730static int nHeightmapOps = NumCmdSpecs(heightmapOps);
     1731
     1732static int
     1733HeightMapCmd(ClientData clientData, Tcl_Interp *interp, int objc,
     1734             Tcl_Obj *const *objv)
     1735{
     1736    Tcl_ObjCmdProc *proc;
     1737
     1738    proc = Rappture::GetOpFromObj(interp, nHeightmapOps, heightmapOps,
    9051739                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
    9061740    if (proc == NULL) {
     
    9471781
    9481782#ifdef DEBUG
    949     writeTGAFile("/tmp/legend.tga", imgData->GetPointer(0), width, height);
     1783    writeTGAFile("/tmp/legend.tga", imgData->GetPointer(0), width, height,
     1784                 TARGA_BYTES_PER_PIXEL);
    9501785#else
    9511786    char cmd[256];
    9521787    snprintf(cmd, sizeof(cmd), "nv>legend %s", name);
     1788#ifdef RENDER_TARGA
     1789    writeTGA(g_fdOut, cmd, imgData->GetPointer(0), width, height,
     1790                 TARGA_BYTES_PER_PIXEL);
     1791#else
    9531792    writePPM(g_fdOut, cmd, imgData->GetPointer(0), width, height);
     1793#endif
    9541794#endif
    9551795
     
    11021942
    11031943static Rappture::CmdSpec pseudoColorOps[] = {
    1104     {"add", 1, PseudoColorAddOp, 2, 3, "?dataSetName?"},
    1105     {"colormap", 1, PseudoColorColorMapOp, 3, 4, "colorMapName ?dataSetName?"},
    1106     {"delete", 1, PseudoColorDeleteOp, 2, 3, "?dataSetName?"},
    1107     {"edges", 1, PseudoColorEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
    1108     {"lighting", 3, PseudoColorLightingOp, 3, 4, "bool ?dataSetName?"},
     1944    {"add",       1, PseudoColorAddOp, 2, 3, "?dataSetName?"},
     1945    {"colormap",  1, PseudoColorColorMapOp, 3, 4, "colorMapName ?dataSetName?"},
     1946    {"delete",    1, PseudoColorDeleteOp, 2, 3, "?dataSetName?"},
     1947    {"edges",     1, PseudoColorEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
     1948    {"lighting",  3, PseudoColorLightingOp, 3, 4, "bool ?dataSetName?"},
    11091949    {"linecolor", 5, PseudoColorLineColorOp, 5, 6, "r g b ?dataSetName?"},
    11101950    {"linewidth", 5, PseudoColorLineWidthOp, 3, 4, "width ?dataSetName?"},
    1111     {"opacity", 1, PseudoColorOpacityOp, 3, 4, "value ?dataSetName?"},
    1112     {"visible", 1, PseudoColorVisibleOp, 3, 4, "bool ?dataSetName?"}
     1951    {"opacity",   1, PseudoColorOpacityOp, 3, 4, "value ?dataSetName?"},
     1952    {"visible",   1, PseudoColorVisibleOp, 3, 4, "bool ?dataSetName?"}
    11131953};
    11141954static int nPseudoColorOps = NumCmdSpecs(pseudoColorOps);
     
    12952135
    12962136static Rappture::CmdSpec polyDataOps[] = {
    1297     {"add", 1, PolyDataAddOp, 2, 3, "?dataSetName?"},
    1298     {"color", 1, PolyDataColorOp, 5, 6, "r g b ?dataSetName?"},
    1299     {"delete", 1, PolyDataDeleteOp, 2, 3, "?dataSetName?"},
    1300     {"edges", 1, PolyDataEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
    1301     {"lighting", 3, PolyDataLightingOp, 3, 4, "bool ?dataSetName?"},
     2137    {"add",       1, PolyDataAddOp, 2, 3, "?dataSetName?"},
     2138    {"color",     1, PolyDataColorOp, 5, 6, "r g b ?dataSetName?"},
     2139    {"delete",    1, PolyDataDeleteOp, 2, 3, "?dataSetName?"},
     2140    {"edges",     1, PolyDataEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
     2141    {"lighting",  3, PolyDataLightingOp, 3, 4, "bool ?dataSetName?"},
    13022142    {"linecolor", 5, PolyDataLineColorOp, 5, 6, "r g b ?dataSetName?"},
    13032143    {"linewidth", 5, PolyDataLineWidthOp, 3, 4, "width ?dataSetName?"},
    1304     {"opacity", 1, PolyDataOpacityOp, 3, 4, "value ?dataSetName?"},
    1305     {"visible", 1, PolyDataVisibleOp, 3, 4, "bool ?dataSetName?"},
     2144    {"opacity",   1, PolyDataOpacityOp, 3, 4, "value ?dataSetName?"},
     2145    {"visible",   1, PolyDataVisibleOp, 3, 4, "bool ?dataSetName?"},
    13062146    {"wireframe", 1, PolyDataWireframeOp, 3, 4, "bool ?dataSetName?"}
    13072147};
     
    13152155
    13162156    proc = Rappture::GetOpFromObj(interp, nPolyDataOps, polyDataOps,
     2157                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
     2158    if (proc == NULL) {
     2159        return TCL_ERROR;
     2160    }
     2161    return (*proc) (clientData, interp, objc, objv);
     2162}
     2163
     2164static int
     2165RendererDepthPeelingOp(ClientData clientData, Tcl_Interp *interp, int objc,
     2166                       Tcl_Obj *const *objv)
     2167{
     2168    bool state;
     2169    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
     2170        return TCL_ERROR;
     2171    }
     2172    g_renderer->setUseDepthPeeling(state);
     2173    return TCL_OK;
     2174}
     2175
     2176static Rappture::CmdSpec rendererOps[] = {
     2177    {"depthpeel", 1, RendererDepthPeelingOp, 3, 3, "bool"}
     2178};
     2179static int nRendererOps = NumCmdSpecs(rendererOps);
     2180
     2181static int
     2182RendererCmd(ClientData clientData, Tcl_Interp *interp, int objc,
     2183            Tcl_Obj *const *objv)
     2184{
     2185    Tcl_ObjCmdProc *proc;
     2186
     2187    proc = Rappture::GetOpFromObj(interp, nRendererOps, rendererOps,
    13172188                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
    13182189    if (proc == NULL) {
     
    13662237
    13672238    proc = Rappture::GetOpFromObj(interp, nScreenOps, screenOps,
     2239                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
     2240    if (proc == NULL) {
     2241        return TCL_ERROR;
     2242    }
     2243    return (*proc) (clientData, interp, objc, objv);
     2244}
     2245
     2246static int
     2247VolumeAddOp(ClientData clientData, Tcl_Interp *interp, int objc,
     2248            Tcl_Obj *const *objv)
     2249{
     2250    if (objc == 3) {
     2251        const char *name = Tcl_GetString(objv[2]);
     2252        g_renderer->addVolume(name);
     2253    } else {
     2254        g_renderer->addVolume("all");
     2255    }
     2256    return TCL_OK;
     2257}
     2258
     2259static int
     2260VolumeColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc,
     2261                 Tcl_Obj *const *objv)
     2262{
     2263    const char *colorMapName = Tcl_GetString(objv[2]);
     2264    if (objc == 4) {
     2265        const char *dataSetName = Tcl_GetString(objv[3]);
     2266        g_renderer->setVolumeColorMap(dataSetName, colorMapName);
     2267    } else {
     2268        g_renderer->setVolumeColorMap("all", colorMapName);
     2269    }
     2270    return TCL_OK;
     2271}
     2272
     2273static int
     2274VolumeDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc,
     2275               Tcl_Obj *const *objv)
     2276{
     2277    if (objc == 3) {
     2278        const char *name = Tcl_GetString(objv[2]);
     2279        g_renderer->deleteVolume(name);
     2280    } else {
     2281        g_renderer->deleteVolume("all");
     2282    }
     2283    return TCL_OK;
     2284}
     2285
     2286static int
     2287VolumeLightingOp(ClientData clientData, Tcl_Interp *interp, int objc,
     2288                 Tcl_Obj *const *objv)
     2289{
     2290    bool state;
     2291    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
     2292        return TCL_ERROR;
     2293    }
     2294    if (objc == 4) {
     2295        const char *name = Tcl_GetString(objv[3]);
     2296        g_renderer->setVolumeLighting(name, state);
     2297    } else {
     2298        g_renderer->setVolumeLighting("all", state);
     2299    }
     2300    return TCL_OK;
     2301}
     2302
     2303static int
     2304VolumeOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc,
     2305                Tcl_Obj *const *objv)
     2306{
     2307    double opacity;
     2308    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
     2309        return TCL_ERROR;
     2310    }
     2311    if (objc == 4) {
     2312        const char *name = Tcl_GetString(objv[3]);
     2313        g_renderer->setVolumeOpacity(name, opacity);
     2314    } else {
     2315        g_renderer->setVolumeOpacity("all", opacity);
     2316    }
     2317    return TCL_OK;
     2318}
     2319
     2320static int
     2321VolumeShadingAmbientOp(ClientData clientData, Tcl_Interp *interp, int objc,
     2322                       Tcl_Obj *const *objv)
     2323{
     2324    double coeff;
     2325    if (Tcl_GetDoubleFromObj(interp, objv[3], &coeff) != TCL_OK) {
     2326        return TCL_ERROR;
     2327    }
     2328
     2329    if (objc == 5) {
     2330        const char *name = Tcl_GetString(objv[4]);
     2331        g_renderer->setVolumeAmbient(name, coeff);
     2332    } else {
     2333        g_renderer->setVolumeAmbient("all", coeff);
     2334    }
     2335    return TCL_OK;
     2336}
     2337
     2338static int
     2339VolumeShadingDiffuseOp(ClientData clientData, Tcl_Interp *interp, int objc,
     2340                       Tcl_Obj *const *objv)
     2341{
     2342    double coeff;
     2343    if (Tcl_GetDoubleFromObj(interp, objv[3], &coeff) != TCL_OK) {
     2344        return TCL_ERROR;
     2345    }
     2346
     2347    if (objc == 5) {
     2348        const char *name = Tcl_GetString(objv[4]);
     2349        g_renderer->setVolumeDiffuse(name, coeff);
     2350    } else {
     2351        g_renderer->setVolumeDiffuse("all", coeff);
     2352    }
     2353    return TCL_OK;
     2354}
     2355
     2356static int
     2357VolumeShadingSpecularOp(ClientData clientData, Tcl_Interp *interp, int objc,
     2358                        Tcl_Obj *const *objv)
     2359{
     2360    double coeff, power;
     2361    if (Tcl_GetDoubleFromObj(interp, objv[3], &coeff) != TCL_OK ||
     2362        Tcl_GetDoubleFromObj(interp, objv[4], &power) != TCL_OK) {
     2363        return TCL_ERROR;
     2364    }
     2365
     2366    if (objc == 6) {
     2367        const char *name = Tcl_GetString(objv[5]);
     2368        g_renderer->setVolumeSpecular(name, coeff, power);
     2369    } else {
     2370        g_renderer->setVolumeSpecular("all", coeff, power);
     2371    }
     2372    return TCL_OK;
     2373}
     2374
     2375static Rappture::CmdSpec volumeShadingOps[] = {
     2376    {"ambient",  1, VolumeShadingAmbientOp, 4, 5, "coeff ?dataSetName?"},
     2377    {"diffuse",  1, VolumeShadingDiffuseOp, 4, 5, "coeff ?dataSetName?"},
     2378    {"specular", 1, VolumeShadingSpecularOp, 5, 6, "coeff power ?dataSetName?"}
     2379};
     2380static int nVolumeShadingOps = NumCmdSpecs(volumeShadingOps);
     2381
     2382static int
     2383VolumeShadingOp(ClientData clientData, Tcl_Interp *interp, int objc,
     2384                Tcl_Obj *const *objv)
     2385{
     2386    Tcl_ObjCmdProc *proc;
     2387
     2388    proc = Rappture::GetOpFromObj(interp, nVolumeShadingOps, volumeShadingOps,
     2389                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
     2390    if (proc == NULL) {
     2391        return TCL_ERROR;
     2392    }
     2393    return (*proc) (clientData, interp, objc, objv);
     2394}
     2395
     2396static int
     2397VolumeVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc,
     2398                Tcl_Obj *const *objv)
     2399{
     2400    bool state;
     2401    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
     2402        return TCL_ERROR;
     2403    }
     2404    if (objc == 4) {
     2405        const char *name = Tcl_GetString(objv[3]);
     2406        g_renderer->setVolumeVisibility(name, state);
     2407    } else {
     2408        g_renderer->setVolumeVisibility("all", state);
     2409    }
     2410    return TCL_OK;
     2411}
     2412
     2413static Rappture::CmdSpec volumeOps[] = {
     2414    {"add",      1, VolumeAddOp, 2, 3, "?dataSetName?"},
     2415    {"colormap", 1, VolumeColorMapOp, 3, 4, "colorMapName ?dataSetName?"},
     2416    {"delete",   1, VolumeDeleteOp, 2, 3, "?dataSetName?"},
     2417    {"lighting", 1, VolumeLightingOp, 3, 4, "bool ?dataSetName?"},
     2418    {"opacity",  1, VolumeOpacityOp, 3, 4, "val ?dataSetName?"},
     2419    {"shading",  1, VolumeShadingOp, 4, 6, "oper val ?dataSetName?"},
     2420    {"visible",  1, VolumeVisibleOp, 3, 4, "bool ?dataSetName?"}
     2421};
     2422static int nVolumeOps = NumCmdSpecs(volumeOps);
     2423
     2424static int
     2425VolumeCmd(ClientData clientData, Tcl_Interp *interp, int objc,
     2426          Tcl_Obj *const *objv)
     2427{
     2428    Tcl_ObjCmdProc *proc;
     2429
     2430    proc = Rappture::GetOpFromObj(interp, nVolumeOps, volumeOps,
    13682431                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
    13692432    if (proc == NULL) {
     
    14692532    Tcl_CreateObjCommand(interp, "colormap",    ColorMapCmd,    NULL, NULL);
    14702533    Tcl_CreateObjCommand(interp, "contour2d",   Contour2DCmd,   NULL, NULL);
     2534    Tcl_CreateObjCommand(interp, "contour3d",   Contour3DCmd,   NULL, NULL);
    14712535    Tcl_CreateObjCommand(interp, "dataset",     DataSetCmd,     NULL, NULL);
     2536    Tcl_CreateObjCommand(interp, "glyphs",      GlyphsCmd,      NULL, NULL);
     2537    Tcl_CreateObjCommand(interp, "heightmap",   HeightMapCmd,   NULL, NULL);
    14722538    Tcl_CreateObjCommand(interp, "legend",      LegendCmd,      NULL, NULL);
    14732539    Tcl_CreateObjCommand(interp, "polydata",    PolyDataCmd,    NULL, NULL);
    14742540    Tcl_CreateObjCommand(interp, "pseudocolor", PseudoColorCmd, NULL, NULL);
     2541    Tcl_CreateObjCommand(interp, "renderer",    RendererCmd,    NULL, NULL);
    14752542    Tcl_CreateObjCommand(interp, "screen",      ScreenCmd,      NULL, NULL);
     2543    Tcl_CreateObjCommand(interp, "volume",      VolumeCmd,      NULL, NULL);
    14762544    return interp;
    14772545}
     2546
     2547/**
     2548 * \brief Delete Tcl commands and interpreter
     2549 *
     2550 */
     2551void Rappture::VtkVis::exitTcl(Tcl_Interp *interp)
     2552{
     2553
     2554    Tcl_DeleteCommand(interp, "axis");
     2555    Tcl_DeleteCommand(interp, "camera");
     2556    Tcl_DeleteCommand(interp, "colormap");
     2557    Tcl_DeleteCommand(interp, "contour2d");
     2558    Tcl_DeleteCommand(interp, "contour3d");
     2559    Tcl_DeleteCommand(interp, "dataset");
     2560    Tcl_DeleteCommand(interp, "glyphs");
     2561    Tcl_DeleteCommand(interp, "heightmap");
     2562    Tcl_DeleteCommand(interp, "legend");
     2563    Tcl_DeleteCommand(interp, "polydata");
     2564    Tcl_DeleteCommand(interp, "pseudocolor");
     2565    Tcl_DeleteCommand(interp, "renderer");
     2566    Tcl_DeleteCommand(interp, "screen");
     2567    Tcl_DeleteCommand(interp, "volume");
     2568
     2569    Tcl_DeleteInterp(interp);
     2570}
  • branches/blt4/packages/vizservers/vtkvis/RpVtkRendererCmd.h

    r2120 r2302  
    1717extern int processCommands(Tcl_Interp *interp, FILE *fin, FILE *fout);
    1818extern Tcl_Interp *initTcl();
     19extern void exitTcl(Tcl_Interp *interp);
    1920
    2021}
  • branches/blt4/packages/vizservers/vtkvis/TGAWriter.cpp

    r2120 r2302  
    2121 * \brief Writes image command + data to supplied file descriptor.
    2222 *
    23  * The image data must be supplied in BGR order with bottom to
     23 * The image data must be supplied in BGR(A) order with bottom to
    2424 * top scanline ordering.
     25 *
     26 * \param[in] fd File descriptor that will be written to
     27 * \param[in] cmdName Command name to send (byte length will be appended)
     28 * \param[in] data Image data
     29 * \param[in] width Width of image in pixels
     30 * \param[in] height Height of image in pixels
     31 * \param[in] bytesPerPixel Should be 3 or 4, depending on alpha
    2532 */
    2633void
    27 Rappture::VtkVis::writeTGA(int fd, const char *cmdName, const unsigned char *data,
    28                            int width, int height)
     34Rappture::VtkVis::writeTGA(int fd, const char *cmdName,
     35                           const unsigned char *data,
     36                           int width, int height,
     37                           int bytesPerPixel)
    2938{
    3039    TRACE("(%dx%d)\n", width, height);
     
    3948    header[14] = (char)height;
    4049    header[15] = (char)(height >> 8);
    41     header[16] = (char)24; // bits per pixel
     50    header[16] = (char)(bytesPerPixel*8); // bits per pixel
    4251
    43     size_t dataLength = width * height * 3;
     52    size_t dataLength = width * height * bytesPerPixel;
    4453
    4554    char command[200];
    46     snprintf(command, sizeof(command), "%simage -type image -bytes %lu\n", cmdName,
     55    snprintf(command, sizeof(command), "%s %lu\n", cmdName,
    4756             (unsigned long)headerLength + dataLength);
    4857
     
    5968    iov[1].iov_base = header;
    6069    iov[1].iov_len = headerLength;
    61     // Image data **must be BGR!**
     70    // Image data **must be BGR(A)!**
    6271    iov[2].iov_base = const_cast<unsigned char *>(data);
    6372    iov[2].iov_len = dataLength;
     
    7483 * \brief Writes image data to supplied file name
    7584 *
    76  * The image data must be supplied in BGR order with bottom to
    77  * top scanline ordering.
     85 * The image data must be supplied with bottom to top
     86 * scanline ordering.  Source data should have BGR(A)
     87 * ordering, unless srcIsRGB is true, in which case
     88 * the source data will be converted from RGB(A) to
     89 * BGR(A).  Note that this is slow and it is better
     90 * to pass in BGR(A) data.
     91 *
     92 * \param[in] filename Path to file that will be written
     93 * \param[in] imgData Image data
     94 * \param[in] width Width of image in pixels
     95 * \param[in] height Height of image in pixels
     96 * \param[in] bytesPerPixel Should be 3 or 4, depending on alpha
     97 * \param[in] srcIsRGB If true source data will be re-ordered
    7898 */
    7999void
    80 Rappture::VtkVis::writeTGAFile(const char *filename, const unsigned char *imgData,
    81                                int width, int height)
     100Rappture::VtkVis::writeTGAFile(const char *filename,
     101                               const unsigned char *imgData,
     102                               int width, int height,
     103                               int bytesPerPixel,
     104                               bool srcIsRGB)
    82105{
    83106    TRACE("%s (%dx%d)\n", filename, width, height);
     
    91114    header[14] = (char)height;
    92115    header[15] = (char)(height >> 8);
    93     header[16] = (char)24; // bits per pixel
     116    header[16] = (char)(bytesPerPixel*8); // bits per pixel
    94117
    95118    outfile.write(header, sizeof(header));
    96119
    97     // RGB -> BGR
    98     for (int i = 0; i < width * height; i++) {
    99         outfile << imgData[i*3+2]
    100                 << imgData[i*3+1]
    101                 << imgData[i*3];
     120    if (!srcIsRGB) {
     121        outfile.write((const char *)imgData, width * height * bytesPerPixel);
     122    } else {
     123        // RGB(A) -> BGR(A)
     124        for (int i = 0; i < width * height; i++) {
     125            outfile << imgData[i*bytesPerPixel+2]
     126                    << imgData[i*bytesPerPixel+1]
     127                    << imgData[i*bytesPerPixel];
     128            if (bytesPerPixel == 4) {
     129                outfile << imgData[i*bytesPerPixel+3];
     130            }
     131        }
    102132    }
    103133
  • branches/blt4/packages/vizservers/vtkvis/TGAWriter.h

    r2120 r2302  
    1313
    1414extern
    15 void writeTGA(int fd, const char *cmdName, const unsigned char *data, int width, int height);
     15void writeTGA(int fd, const char *cmdName, const unsigned char *data,
     16              int width, int height, int bytesPerPixel);
    1617
    1718extern
    18 void writeTGAFile(const char *filename, const unsigned char *data, int width, int height);
     19void writeTGAFile(const char *filename, const unsigned char *data,
     20                  int width, int height, int bytesPerPixel,
     21                  bool srcIsRGB = false);
    1922
    2023}
Note: See TracChangeset for help on using the changeset viewer.