/*****************************************************************************
*
* Copyright (c) 2000 - 2007, The Regents of the University of California
* Produced at the Lawrence Livermore National Laboratory
* All rights reserved.
*
* This file is part of VisIt. For details, see http://www.llnl.gov/visit/. The
* full copyright notice is contained in the file COPYRIGHT located at the root
* of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html.
*
* Redistribution  and  use  in  source  and  binary  forms,  with  or  without
* modification, are permitted provided that the following conditions are met:
*
*  - Redistributions of  source code must  retain the above  copyright notice,
*    this list of conditions and the disclaimer below.
*  - Redistributions in binary form must reproduce the above copyright notice,
*    this  list of  conditions  and  the  disclaimer (as noted below)  in  the
*    documentation and/or materials provided with the distribution.
*  - Neither the name of the UC/LLNL nor  the names of its contributors may be
*    used to  endorse or  promote products derived from  this software without
*    specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT  HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR  IMPLIED WARRANTIES, INCLUDING,  BUT NOT  LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR  PURPOSE
* ARE  DISCLAIMED.  IN  NO  EVENT  SHALL  THE  REGENTS  OF  THE  UNIVERSITY OF
* CALIFORNIA, THE U.S.  DEPARTMENT  OF  ENERGY OR CONTRIBUTORS BE  LIABLE  FOR
* ANY  DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT  LIMITED TO, PROCUREMENT OF  SUBSTITUTE GOODS OR
* SERVICES; LOSS OF  USE, DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER
* CAUSED  AND  ON  ANY  THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT
* LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY  WAY
* OUT OF THE  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
*****************************************************************************/

#include <cmath>
#include <VolumeAttributes.h>
#include <DataNode.h>
#include <ColorControlPoint.h>
#include <GaussianControlPoint.h>

namespace pointsprite {
//
// Enum conversion methods for VolumeAttributes::Renderer
//

static const char *Renderer_strings[] = {
"Splatting", "Texture3D", "RayCasting",
"RayCastingIntegration"};

std::string
VolumeAttributes::Renderer_ToString(VolumeAttributes::Renderer t)
{
    int index = int(t);
    if(index < 0 || index >= 4) index = 0;
    return Renderer_strings[index];
}

std::string
VolumeAttributes::Renderer_ToString(int t)
{
    int index = (t < 0 || t >= 4) ? 0 : t;
    return Renderer_strings[index];
}

bool
VolumeAttributes::Renderer_FromString(const std::string &s, VolumeAttributes::Renderer &val)
{
    val = VolumeAttributes::Splatting;
    for(int i = 0; i < 4; ++i)
    {
        if(s == Renderer_strings[i])
        {
            val = (Renderer)i;
            return true;
        }
    }
    return false;
}

//
// Enum conversion methods for VolumeAttributes::GradientType
//

static const char *GradientType_strings[] = {
"CenteredDifferences", "SobelOperator"};

std::string
VolumeAttributes::GradientType_ToString(VolumeAttributes::GradientType t)
{
    int index = int(t);
    if(index < 0 || index >= 2) index = 0;
    return GradientType_strings[index];
}

std::string
VolumeAttributes::GradientType_ToString(int t)
{
    int index = (t < 0 || t >= 2) ? 0 : t;
    return GradientType_strings[index];
}

bool
VolumeAttributes::GradientType_FromString(const std::string &s, VolumeAttributes::GradientType &val)
{
    val = VolumeAttributes::CenteredDifferences;
    for(int i = 0; i < 2; ++i)
    {
        if(s == GradientType_strings[i])
        {
            val = (GradientType)i;
            return true;
        }
    }
    return false;
}

//
// Enum conversion methods for VolumeAttributes::Scaling
//

static const char *Scaling_strings[] = {
"Linear", "Log10", "Skew"
};

std::string
VolumeAttributes::Scaling_ToString(VolumeAttributes::Scaling t)
{
    int index = int(t);
    if(index < 0 || index >= 3) index = 0;
    return Scaling_strings[index];
}

std::string
VolumeAttributes::Scaling_ToString(int t)
{
    int index = (t < 0 || t >= 3) ? 0 : t;
    return Scaling_strings[index];
}

bool
VolumeAttributes::Scaling_FromString(const std::string &s, VolumeAttributes::Scaling &val)
{
    val = VolumeAttributes::Linear;
    for(int i = 0; i < 3; ++i)
    {
        if(s == Scaling_strings[i])
        {
            val = (Scaling)i;
            return true;
        }
    }
    return false;
}

//
// Enum conversion methods for VolumeAttributes::SamplingType
//

static const char *SamplingType_strings[] = {
"KernelBased", "Rasterization"};

std::string
VolumeAttributes::SamplingType_ToString(VolumeAttributes::SamplingType t)
{
    int index = int(t);
    if(index < 0 || index >= 2) index = 0;
    return SamplingType_strings[index];
}

std::string
VolumeAttributes::SamplingType_ToString(int t)
{
    int index = (t < 0 || t >= 2) ? 0 : t;
    return SamplingType_strings[index];
}

bool
VolumeAttributes::SamplingType_FromString(const std::string &s, VolumeAttributes::SamplingType &val)
{
    val = VolumeAttributes::KernelBased;
    for(int i = 0; i < 2; ++i)
    {
        if(s == SamplingType_strings[i])
        {
            val = (SamplingType)i;
            return true;
        }
    }
    return false;
}

// Type map format string
const char *VolumeAttributes::TypeMapFormatString = "bbafbaisUbfbfbfbfbiiiiidi";

// ****************************************************************************
// Method: VolumeAttributes::VolumeAttributes
//
// Purpose:
//   Constructor for the VolumeAttributes class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   Tue Mar 13 14:48:06 PST 2007
//
// Modifications:
//
// ****************************************************************************

VolumeAttributes::VolumeAttributes() :
    AttributeSubject(VolumeAttributes::TypeMapFormatString),
    opacityVariable("default")
{
    legendFlag = true;
    lightingFlag = true;
    SetDefaultColorControlPoints();
    opacityAttenuation = 1;
    freeformFlag = true;
    resampleTarget = 50000;
    for(int i = 0; i < 256; ++i)
        freeformOpacity[i] = (unsigned char)i;
    useColorVarMin = false;
    colorVarMin = 0;
    useColorVarMax = false;
    colorVarMax = 0;
    useOpacityVarMin = false;
    opacityVarMin = 0;
    useOpacityVarMax = false;
    opacityVarMax = 0;
    smoothData = false;
    samplesPerRay = 500;
    rendererType = Splatting;
    gradientType = SobelOperator;
    num3DSlices = 200;
    scaling = Linear;
    skewFactor = 1;
    sampling = Rasterization;
}

// ****************************************************************************
// Method: VolumeAttributes::VolumeAttributes
//
// Purpose:
//   Copy constructor for the VolumeAttributes class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   Tue Mar 13 14:48:06 PST 2007
//
// Modifications:
//
// ****************************************************************************

VolumeAttributes::VolumeAttributes(const VolumeAttributes &obj) :
    AttributeSubject(VolumeAttributes::TypeMapFormatString)
{
    int i;

    legendFlag = obj.legendFlag;
    lightingFlag = obj.lightingFlag;
    colorControlPoints = obj.colorControlPoints;
    opacityAttenuation = obj.opacityAttenuation;
    freeformFlag = obj.freeformFlag;
    opacityControlPoints = obj.opacityControlPoints;
    resampleTarget = obj.resampleTarget;
    opacityVariable = obj.opacityVariable;
    for(i = 0; i < 256; ++i)
        freeformOpacity[i] = obj.freeformOpacity[i];

    useColorVarMin = obj.useColorVarMin;
    colorVarMin = obj.colorVarMin;
    useColorVarMax = obj.useColorVarMax;
    colorVarMax = obj.colorVarMax;
    useOpacityVarMin = obj.useOpacityVarMin;
    opacityVarMin = obj.opacityVarMin;
    useOpacityVarMax = obj.useOpacityVarMax;
    opacityVarMax = obj.opacityVarMax;
    smoothData = obj.smoothData;
    samplesPerRay = obj.samplesPerRay;
    rendererType = obj.rendererType;
    gradientType = obj.gradientType;
    num3DSlices = obj.num3DSlices;
    scaling = obj.scaling;
    skewFactor = obj.skewFactor;
    sampling = obj.sampling;

    SelectAll();
}

// ****************************************************************************
// Method: VolumeAttributes::~VolumeAttributes
//
// Purpose:
//   Destructor for the VolumeAttributes class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   Tue Mar 13 14:48:06 PST 2007
//
// Modifications:
//
// ****************************************************************************

VolumeAttributes::~VolumeAttributes()
{
    // nothing here
}

// ****************************************************************************
// Method: VolumeAttributes::operator =
//
// Purpose:
//   Assignment operator for the VolumeAttributes class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   Tue Mar 13 14:48:06 PST 2007
//
// Modifications:
//
// ****************************************************************************

VolumeAttributes&
VolumeAttributes::operator = (const VolumeAttributes &obj)
{
    if (this == &obj) return *this;
    int i;

    legendFlag = obj.legendFlag;
    lightingFlag = obj.lightingFlag;
    colorControlPoints = obj.colorControlPoints;
    opacityAttenuation = obj.opacityAttenuation;
    freeformFlag = obj.freeformFlag;
    opacityControlPoints = obj.opacityControlPoints;
    resampleTarget = obj.resampleTarget;
    opacityVariable = obj.opacityVariable;
    for(i = 0; i < 256; ++i)
        freeformOpacity[i] = obj.freeformOpacity[i];

    useColorVarMin = obj.useColorVarMin;
    colorVarMin = obj.colorVarMin;
    useColorVarMax = obj.useColorVarMax;
    colorVarMax = obj.colorVarMax;
    useOpacityVarMin = obj.useOpacityVarMin;
    opacityVarMin = obj.opacityVarMin;
    useOpacityVarMax = obj.useOpacityVarMax;
    opacityVarMax = obj.opacityVarMax;
    smoothData = obj.smoothData;
    samplesPerRay = obj.samplesPerRay;
    rendererType = obj.rendererType;
    gradientType = obj.gradientType;
    num3DSlices = obj.num3DSlices;
    scaling = obj.scaling;
    skewFactor = obj.skewFactor;
    sampling = obj.sampling;

    SelectAll();
    return *this;
}

// ****************************************************************************
// Method: VolumeAttributes::operator ==
//
// Purpose:
//   Comparison operator == for the VolumeAttributes class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   Tue Mar 13 14:48:06 PST 2007
//
// Modifications:
//
// ****************************************************************************

bool
VolumeAttributes::operator == (const VolumeAttributes &obj) const
{
    int i;

    // Compare the freeformOpacity arrays.
    bool freeformOpacity_equal = true;
    for(i = 0; i < 256 && freeformOpacity_equal; ++i)
        freeformOpacity_equal = (freeformOpacity[i] == obj.freeformOpacity[i]);

    // Create the return value
    return ((legendFlag == obj.legendFlag) &&
            (lightingFlag == obj.lightingFlag) &&
            (colorControlPoints == obj.colorControlPoints) &&
            (opacityAttenuation == obj.opacityAttenuation) &&
            (freeformFlag == obj.freeformFlag) &&
            (opacityControlPoints == obj.opacityControlPoints) &&
            (resampleTarget == obj.resampleTarget) &&
            (opacityVariable == obj.opacityVariable) &&
            freeformOpacity_equal &&
            (useColorVarMin == obj.useColorVarMin) &&
            (colorVarMin == obj.colorVarMin) &&
            (useColorVarMax == obj.useColorVarMax) &&
            (colorVarMax == obj.colorVarMax) &&
            (useOpacityVarMin == obj.useOpacityVarMin) &&
            (opacityVarMin == obj.opacityVarMin) &&
            (useOpacityVarMax == obj.useOpacityVarMax) &&
            (opacityVarMax == obj.opacityVarMax) &&
            (smoothData == obj.smoothData) &&
            (samplesPerRay == obj.samplesPerRay) &&
            (rendererType == obj.rendererType) &&
            (gradientType == obj.gradientType) &&
            (num3DSlices == obj.num3DSlices) &&
            (scaling == obj.scaling) &&
            (skewFactor == obj.skewFactor) &&
            (sampling == obj.sampling));
}

// ****************************************************************************
// Method: VolumeAttributes::operator !=
//
// Purpose:
//   Comparison operator != for the VolumeAttributes class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   Tue Mar 13 14:48:06 PST 2007
//
// Modifications:
//
// ****************************************************************************

bool
VolumeAttributes::operator != (const VolumeAttributes &obj) const
{
    return !(this->operator == (obj));
}

// ****************************************************************************
// Method: VolumeAttributes::TypeName
//
// Purpose:
//   Type name method for the VolumeAttributes class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   Tue Mar 13 14:48:06 PST 2007
//
// Modifications:
//
// ****************************************************************************

const std::string
VolumeAttributes::TypeName() const
{
    return "VolumeAttributes";
}

// ****************************************************************************
// Method: VolumeAttributes::CopyAttributes
//
// Purpose:
//   CopyAttributes method for the VolumeAttributes class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   Tue Mar 13 14:48:06 PST 2007
//
// Modifications:
//
// ****************************************************************************

bool
VolumeAttributes::CopyAttributes(const AttributeGroup *atts)
{
    if(TypeName() != atts->TypeName())
        return false;

    // Call assignment operator.
    const VolumeAttributes *tmp = (const VolumeAttributes *)atts;
    *this = *tmp;

    return true;
}

// ****************************************************************************
// Method: VolumeAttributes::CreateCompatible
//
// Purpose:
//   CreateCompatible method for the VolumeAttributes class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   Tue Mar 13 14:48:06 PST 2007
//
// Modifications:
//
// ****************************************************************************

AttributeSubject *
VolumeAttributes::CreateCompatible(const std::string &tname) const
{
    AttributeSubject *retval = 0;
    if(TypeName() == tname)
        retval = new VolumeAttributes(*this);
    // Other cases could go here too.

    return retval;
}

// ****************************************************************************
// Method: VolumeAttributes::NewInstance
//
// Purpose:
//   NewInstance method for the VolumeAttributes class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   Tue Mar 13 14:48:06 PST 2007
//
// Modifications:
//
// ****************************************************************************

AttributeSubject *
VolumeAttributes::NewInstance(bool copy) const
{
    AttributeSubject *retval = 0;
    if(copy)
        retval = new VolumeAttributes(*this);
    else
        retval = new VolumeAttributes;

    return retval;
}

// ****************************************************************************
// Method: VolumeAttributes::SelectAll
//
// Purpose:
//   Selects all attributes.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   Tue Mar 13 14:48:06 PST 2007
//
// Modifications:
//
// ****************************************************************************

void
VolumeAttributes::SelectAll()
{
    Select(0, (void *)&legendFlag);
    Select(1, (void *)&lightingFlag);
    Select(2, (void *)&colorControlPoints);
    Select(3, (void *)&opacityAttenuation);
    Select(4, (void *)&freeformFlag);
    Select(5, (void *)&opacityControlPoints);
    Select(6, (void *)&resampleTarget);
    Select(7, (void *)&opacityVariable);
    Select(8, (void *)freeformOpacity, 256);
    Select(9, (void *)&useColorVarMin);
    Select(10, (void *)&colorVarMin);
    Select(11, (void *)&useColorVarMax);
    Select(12, (void *)&colorVarMax);
    Select(13, (void *)&useOpacityVarMin);
    Select(14, (void *)&opacityVarMin);
    Select(15, (void *)&useOpacityVarMax);
    Select(16, (void *)&opacityVarMax);
    Select(17, (void *)&smoothData);
    Select(18, (void *)&samplesPerRay);
    Select(19, (void *)&rendererType);
    Select(20, (void *)&gradientType);
    Select(21, (void *)&num3DSlices);
    Select(22, (void *)&scaling);
    Select(23, (void *)&skewFactor);
    Select(24, (void *)&sampling);
}

///////////////////////////////////////////////////////////////////////////////
// Persistence methods
///////////////////////////////////////////////////////////////////////////////

// ****************************************************************************
// Method: VolumeAttributes::CreateNode
//
// Purpose:
//   This method creates a DataNode representation of the object so it can be saved to a config file.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   Tue Mar 13 14:48:06 PST 2007
//
// Modifications:
//
// ****************************************************************************

bool
VolumeAttributes::CreateNode(DataNode *parentNode, bool completeSave, bool forceAdd)
{
    if(parentNode == 0)
        return false;

    VolumeAttributes defaultObject;
    bool addToParent = false;
    // Create a node for VolumeAttributes.
    DataNode *node = new DataNode("VolumeAttributes");

    if(completeSave || !FieldsEqual(0, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("legendFlag", legendFlag));
    }

    if(completeSave || !FieldsEqual(1, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("lightingFlag", lightingFlag));
    }

    if(completeSave || !FieldsEqual(2, &defaultObject))
    {
        DataNode *colorControlPointsNode = new DataNode("colorControlPoints");
        if(colorControlPoints.CreateNode(colorControlPointsNode, completeSave, false))
        {
            addToParent = true;
            node->AddNode(colorControlPointsNode);
        }
        else
            delete colorControlPointsNode;
    }

    if(completeSave || !FieldsEqual(3, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("opacityAttenuation", opacityAttenuation));
    }

    if(completeSave || !FieldsEqual(4, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("freeformFlag", freeformFlag));
    }

    if(completeSave || !FieldsEqual(5, &defaultObject))
    {
        DataNode *opacityControlPointsNode = new DataNode("opacityControlPoints");
        if(opacityControlPoints.CreateNode(opacityControlPointsNode, completeSave, false))
        {
            addToParent = true;
            node->AddNode(opacityControlPointsNode);
        }
        else
            delete opacityControlPointsNode;
    }

    if(completeSave || !FieldsEqual(6, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("resampleTarget", resampleTarget));
    }

    if(completeSave || !FieldsEqual(7, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("opacityVariable", opacityVariable));
    }

    if(completeSave || !FieldsEqual(8, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("freeformOpacity", freeformOpacity, 256));
    }

    if(completeSave || !FieldsEqual(9, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("useColorVarMin", useColorVarMin));
    }

    if(completeSave || !FieldsEqual(10, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("colorVarMin", colorVarMin));
    }

    if(completeSave || !FieldsEqual(11, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("useColorVarMax", useColorVarMax));
    }

    if(completeSave || !FieldsEqual(12, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("colorVarMax", colorVarMax));
    }

    if(completeSave || !FieldsEqual(13, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("useOpacityVarMin", useOpacityVarMin));
    }

    if(completeSave || !FieldsEqual(14, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("opacityVarMin", opacityVarMin));
    }

    if(completeSave || !FieldsEqual(15, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("useOpacityVarMax", useOpacityVarMax));
    }

    if(completeSave || !FieldsEqual(16, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("opacityVarMax", opacityVarMax));
    }

    if(completeSave || !FieldsEqual(17, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("smoothData", smoothData));
    }

    if(completeSave || !FieldsEqual(18, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("samplesPerRay", samplesPerRay));
    }

    if(completeSave || !FieldsEqual(19, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("rendererType", Renderer_ToString(rendererType)));
    }

    if(completeSave || !FieldsEqual(20, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("gradientType", GradientType_ToString(gradientType)));
    }

    if(completeSave || !FieldsEqual(21, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("num3DSlices", num3DSlices));
    }

    if(completeSave || !FieldsEqual(22, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("scaling", Scaling_ToString(scaling)));
    }

    if(completeSave || !FieldsEqual(23, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("skewFactor", skewFactor));
    }

    if(completeSave || !FieldsEqual(24, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("sampling", SamplingType_ToString(sampling)));
    }


    // Add the node to the parent node.
    if(addToParent || forceAdd)
        parentNode->AddNode(node);
    else
        delete node;

    return (addToParent || forceAdd);
}

// ****************************************************************************
// Method: VolumeAttributes::SetFromNode
//
// Purpose:
//   This method sets attributes in this object from values in a DataNode representation of the object.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   Tue Mar 13 14:48:06 PST 2007
//
// Modifications:
//
// ****************************************************************************

void
VolumeAttributes::SetFromNode(DataNode *parentNode)
{
    //int i;
    if(parentNode == 0)
        return;

    DataNode *searchNode = parentNode->GetNode("VolumeAttributes");
    if(searchNode == 0)
        return;

    DataNode *node;
    if((node = searchNode->GetNode("legendFlag")) != 0)
        SetLegendFlag(node->AsBool());
    if((node = searchNode->GetNode("lightingFlag")) != 0)
        SetLightingFlag(node->AsBool());
    if((node = searchNode->GetNode("colorControlPoints")) != 0)
        colorControlPoints.SetFromNode(node);
    if((node = searchNode->GetNode("opacityAttenuation")) != 0)
        SetOpacityAttenuation(node->AsFloat());
    if((node = searchNode->GetNode("freeformFlag")) != 0)
        SetFreeformFlag(node->AsBool());
    if((node = searchNode->GetNode("opacityControlPoints")) != 0)
        opacityControlPoints.SetFromNode(node);
    if((node = searchNode->GetNode("resampleTarget")) != 0)
        SetResampleTarget(node->AsInt());
    if((node = searchNode->GetNode("opacityVariable")) != 0)
        SetOpacityVariable(node->AsString());
    if((node = searchNode->GetNode("freeformOpacity")) != 0)
        SetFreeformOpacity(node->AsUnsignedCharArray());
    if((node = searchNode->GetNode("useColorVarMin")) != 0)
        SetUseColorVarMin(node->AsBool());
    if((node = searchNode->GetNode("colorVarMin")) != 0)
        SetColorVarMin(node->AsFloat());
    if((node = searchNode->GetNode("useColorVarMax")) != 0)
        SetUseColorVarMax(node->AsBool());
    if((node = searchNode->GetNode("colorVarMax")) != 0)
        SetColorVarMax(node->AsFloat());
    if((node = searchNode->GetNode("useOpacityVarMin")) != 0)
        SetUseOpacityVarMin(node->AsBool());
    if((node = searchNode->GetNode("opacityVarMin")) != 0)
        SetOpacityVarMin(node->AsFloat());
    if((node = searchNode->GetNode("useOpacityVarMax")) != 0)
        SetUseOpacityVarMax(node->AsBool());
    if((node = searchNode->GetNode("opacityVarMax")) != 0)
        SetOpacityVarMax(node->AsFloat());
    if((node = searchNode->GetNode("smoothData")) != 0)
        SetSmoothData(node->AsBool());
    if((node = searchNode->GetNode("samplesPerRay")) != 0)
        SetSamplesPerRay(node->AsInt());
    if((node = searchNode->GetNode("rendererType")) != 0)
    {
        // Allow enums to be int or string in the config file
        if(node->GetNodeType() == INT_NODE)
        {
            int ival = node->AsInt();
            if(ival >= 0 && ival < 4)
                SetRendererType(Renderer(ival));
        }
        else if(node->GetNodeType() == STRING_NODE)
        {
            Renderer value;
            if(Renderer_FromString(node->AsString(), value))
                SetRendererType(value);
        }
    }
    if((node = searchNode->GetNode("gradientType")) != 0)
    {
        // Allow enums to be int or string in the config file
        if(node->GetNodeType() == INT_NODE)
        {
            int ival = node->AsInt();
            if(ival >= 0 && ival < 2)
                SetGradientType(GradientType(ival));
        }
        else if(node->GetNodeType() == STRING_NODE)
        {
            GradientType value;
            if(GradientType_FromString(node->AsString(), value))
                SetGradientType(value);
        }
    }
    if((node = searchNode->GetNode("num3DSlices")) != 0)
        SetNum3DSlices(node->AsInt());
    if((node = searchNode->GetNode("scaling")) != 0)
    {
        // Allow enums to be int or string in the config file
        if(node->GetNodeType() == INT_NODE)
        {
            int ival = node->AsInt();
            if(ival >= 0 && ival < 3)
                SetScaling(Scaling(ival));
        }
        else if(node->GetNodeType() == STRING_NODE)
        {
            Scaling value;
            if(Scaling_FromString(node->AsString(), value))
                SetScaling(value);
        }
    }
    if((node = searchNode->GetNode("skewFactor")) != 0)
        SetSkewFactor(node->AsDouble());
    if((node = searchNode->GetNode("sampling")) != 0)
    {
        // Allow enums to be int or string in the config file
        if(node->GetNodeType() == INT_NODE)
        {
            int ival = node->AsInt();
            if(ival >= 0 && ival < 2)
                SetSampling(SamplingType(ival));
        }
        else if(node->GetNodeType() == STRING_NODE)
        {
            SamplingType value;
            if(SamplingType_FromString(node->AsString(), value))
                SetSampling(value);
        }
    }

    if(colorControlPoints.GetNumControlPoints() < 2)
         SetDefaultColorControlPoints();
}

///////////////////////////////////////////////////////////////////////////////
// Set property methods
///////////////////////////////////////////////////////////////////////////////

void
VolumeAttributes::SetLegendFlag(bool legendFlag_)
{
    legendFlag = legendFlag_;
    Select(0, (void *)&legendFlag);
}

void
VolumeAttributes::SetLightingFlag(bool lightingFlag_)
{
    lightingFlag = lightingFlag_;
    Select(1, (void *)&lightingFlag);
}

void
VolumeAttributes::SetColorControlPoints(const ColorControlPointList &colorControlPoints_)
{
    colorControlPoints = colorControlPoints_;
    Select(2, (void *)&colorControlPoints);
}

void
VolumeAttributes::SetOpacityAttenuation(float opacityAttenuation_)
{
    opacityAttenuation = opacityAttenuation_;
    Select(3, (void *)&opacityAttenuation);
}

void
VolumeAttributes::SetFreeformFlag(bool freeformFlag_)
{
    freeformFlag = freeformFlag_;
    Select(4, (void *)&freeformFlag);
}

void
VolumeAttributes::SetOpacityControlPoints(const GaussianControlPointList &opacityControlPoints_)
{
    opacityControlPoints = opacityControlPoints_;
    Select(5, (void *)&opacityControlPoints);
}

void
VolumeAttributes::SetResampleTarget(int resampleTarget_)
{
    resampleTarget = resampleTarget_;
    Select(6, (void *)&resampleTarget);
}

void
VolumeAttributes::SetOpacityVariable(const std::string &opacityVariable_)
{
    opacityVariable = opacityVariable_;
    Select(7, (void *)&opacityVariable);
}

void
VolumeAttributes::SetFreeformOpacity(const unsigned char *freeformOpacity_)
{
    for(int i = 0; i < 256; ++i)
        freeformOpacity[i] = freeformOpacity_[i];
    Select(8, (void *)freeformOpacity, 256);
}

void
VolumeAttributes::SetUseColorVarMin(bool useColorVarMin_)
{
    useColorVarMin = useColorVarMin_;
    Select(9, (void *)&useColorVarMin);
}

void
VolumeAttributes::SetColorVarMin(float colorVarMin_)
{
    colorVarMin = colorVarMin_;
    Select(10, (void *)&colorVarMin);
}

void
VolumeAttributes::SetUseColorVarMax(bool useColorVarMax_)
{
    useColorVarMax = useColorVarMax_;
    Select(11, (void *)&useColorVarMax);
}

void
VolumeAttributes::SetColorVarMax(float colorVarMax_)
{
    colorVarMax = colorVarMax_;
    Select(12, (void *)&colorVarMax);
}

void
VolumeAttributes::SetUseOpacityVarMin(bool useOpacityVarMin_)
{
    useOpacityVarMin = useOpacityVarMin_;
    Select(13, (void *)&useOpacityVarMin);
}

void
VolumeAttributes::SetOpacityVarMin(float opacityVarMin_)
{
    opacityVarMin = opacityVarMin_;
    Select(14, (void *)&opacityVarMin);
}

void
VolumeAttributes::SetUseOpacityVarMax(bool useOpacityVarMax_)
{
    useOpacityVarMax = useOpacityVarMax_;
    Select(15, (void *)&useOpacityVarMax);
}

void
VolumeAttributes::SetOpacityVarMax(float opacityVarMax_)
{
    opacityVarMax = opacityVarMax_;
    Select(16, (void *)&opacityVarMax);
}

void
VolumeAttributes::SetSmoothData(bool smoothData_)
{
    smoothData = smoothData_;
    Select(17, (void *)&smoothData);
}

void
VolumeAttributes::SetSamplesPerRay(int samplesPerRay_)
{
    samplesPerRay = samplesPerRay_;
    Select(18, (void *)&samplesPerRay);
}

void
VolumeAttributes::SetRendererType(VolumeAttributes::Renderer rendererType_)
{
    rendererType = rendererType_;
    Select(19, (void *)&rendererType);
}

void
VolumeAttributes::SetGradientType(VolumeAttributes::GradientType gradientType_)
{
    gradientType = gradientType_;
    Select(20, (void *)&gradientType);
}

void
VolumeAttributes::SetNum3DSlices(int num3DSlices_)
{
    num3DSlices = num3DSlices_;
    Select(21, (void *)&num3DSlices);
}

void
VolumeAttributes::SetScaling(VolumeAttributes::Scaling scaling_)
{
    scaling = scaling_;
    Select(22, (void *)&scaling);
}

void
VolumeAttributes::SetSkewFactor(double skewFactor_)
{
    skewFactor = skewFactor_;
    Select(23, (void *)&skewFactor);
}

void
VolumeAttributes::SetSampling(VolumeAttributes::SamplingType sampling_)
{
    sampling = sampling_;
    Select(24, (void *)&sampling);
}

///////////////////////////////////////////////////////////////////////////////
// Get property methods
///////////////////////////////////////////////////////////////////////////////

bool
VolumeAttributes::GetLegendFlag() const
{
    return legendFlag;
}

bool
VolumeAttributes::GetLightingFlag() const
{
    return lightingFlag;
}

const ColorControlPointList &
VolumeAttributes::GetColorControlPoints() const
{
    return colorControlPoints;
}

ColorControlPointList &
VolumeAttributes::GetColorControlPoints()
{
    return colorControlPoints;
}

float
VolumeAttributes::GetOpacityAttenuation() const
{
    return opacityAttenuation;
}

bool
VolumeAttributes::GetFreeformFlag() const
{
    return freeformFlag;
}

const GaussianControlPointList &
VolumeAttributes::GetOpacityControlPoints() const
{
    return opacityControlPoints;
}

GaussianControlPointList &
VolumeAttributes::GetOpacityControlPoints()
{
    return opacityControlPoints;
}

int
VolumeAttributes::GetResampleTarget() const
{
    return resampleTarget;
}

const std::string &
VolumeAttributes::GetOpacityVariable() const
{
    return opacityVariable;
}

std::string &
VolumeAttributes::GetOpacityVariable()
{
    return opacityVariable;
}

const unsigned char *
VolumeAttributes::GetFreeformOpacity() const
{
    return freeformOpacity;
}

unsigned char *
VolumeAttributes::GetFreeformOpacity()
{
    return freeformOpacity;
}

bool
VolumeAttributes::GetUseColorVarMin() const
{
    return useColorVarMin;
}

float
VolumeAttributes::GetColorVarMin() const
{
    return colorVarMin;
}

bool
VolumeAttributes::GetUseColorVarMax() const
{
    return useColorVarMax;
}

float
VolumeAttributes::GetColorVarMax() const
{
    return colorVarMax;
}

bool
VolumeAttributes::GetUseOpacityVarMin() const
{
    return useOpacityVarMin;
}

float
VolumeAttributes::GetOpacityVarMin() const
{
    return opacityVarMin;
}

bool
VolumeAttributes::GetUseOpacityVarMax() const
{
    return useOpacityVarMax;
}

float
VolumeAttributes::GetOpacityVarMax() const
{
    return opacityVarMax;
}

bool
VolumeAttributes::GetSmoothData() const
{
    return smoothData;
}

int
VolumeAttributes::GetSamplesPerRay() const
{
    return samplesPerRay;
}

VolumeAttributes::Renderer
VolumeAttributes::GetRendererType() const
{
    return Renderer(rendererType);
}

VolumeAttributes::GradientType
VolumeAttributes::GetGradientType() const
{
    return GradientType(gradientType);
}

int
VolumeAttributes::GetNum3DSlices() const
{
    return num3DSlices;
}

VolumeAttributes::Scaling
VolumeAttributes::GetScaling() const
{
    return Scaling(scaling);
}

double
VolumeAttributes::GetSkewFactor() const
{
    return skewFactor;
}

VolumeAttributes::SamplingType
VolumeAttributes::GetSampling() const
{
    return SamplingType(sampling);
}

///////////////////////////////////////////////////////////////////////////////
// Select property methods
///////////////////////////////////////////////////////////////////////////////

void
VolumeAttributes::SelectColorControlPoints()
{
    Select(2, (void *)&colorControlPoints);
}

void
VolumeAttributes::SelectOpacityControlPoints()
{
    Select(5, (void *)&opacityControlPoints);
}

void
VolumeAttributes::SelectOpacityVariable()
{
    Select(7, (void *)&opacityVariable);
}

void
VolumeAttributes::SelectFreeformOpacity()
{
    Select(8, (void *)freeformOpacity, 256);
}

///////////////////////////////////////////////////////////////////////////////
// Keyframing methods
///////////////////////////////////////////////////////////////////////////////

// ****************************************************************************
// Method: VolumeAttributes::GetFieldName
//
// Purpose:
//   This method returns the name of a field given its index.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   Tue Mar 13 14:48:06 PST 2007
//
// Modifications:
//
// ****************************************************************************

std::string
VolumeAttributes::GetFieldName(int index) const
{
    switch (index)
    {
        case 0:  return "legendFlag";
        case 1:  return "lightingFlag";
        case 2:  return "colorControlPoints";
        case 3:  return "opacityAttenuation";
        case 4:  return "freeformFlag";
        case 5:  return "opacityControlPoints";
        case 6:  return "resampleTarget";
        case 7:  return "opacityVariable";
        case 8:  return "freeformOpacity";
        case 9:  return "useColorVarMin";
        case 10:  return "colorVarMin";
        case 11:  return "useColorVarMax";
        case 12:  return "colorVarMax";
        case 13:  return "useOpacityVarMin";
        case 14:  return "opacityVarMin";
        case 15:  return "useOpacityVarMax";
        case 16:  return "opacityVarMax";
        case 17:  return "smoothData";
        case 18:  return "samplesPerRay";
        case 19:  return "Renderer Type";
        case 20:  return "Gradient Type";
        case 21:  return "num3DSlices";
        case 22:  return "scaling";
        case 23:  return "skewFactor";
        case 24:  return "Sampling Type";
        default:  return "invalid index";
    }
}

// ****************************************************************************
// Method: VolumeAttributes::GetFieldType
//
// Purpose:
//   This method returns the type of a field given its index.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   Tue Mar 13 14:48:06 PST 2007
//
// Modifications:
//
// ****************************************************************************

AttributeGroup::FieldType
VolumeAttributes::GetFieldType(int index) const
{
    switch (index)
    {
        case 0:  return FieldType_bool;
        case 1:  return FieldType_bool;
        case 2:  return FieldType_att;
        case 3:  return FieldType_float;
        case 4:  return FieldType_bool;
        case 5:  return FieldType_att;
        case 6:  return FieldType_int;
        case 7:  return FieldType_variablename;
        case 8:  return FieldType_ucharArray;
        case 9:  return FieldType_bool;
        case 10:  return FieldType_float;
        case 11:  return FieldType_bool;
        case 12:  return FieldType_float;
        case 13:  return FieldType_bool;
        case 14:  return FieldType_float;
        case 15:  return FieldType_bool;
        case 16:  return FieldType_float;
        case 17:  return FieldType_bool;
        case 18:  return FieldType_int;
        case 19:  return FieldType_enum;
        case 20:  return FieldType_enum;
        case 21:  return FieldType_int;
        case 22:  return FieldType_enum;
        case 23:  return FieldType_double;
        case 24:  return FieldType_enum;
        default:  return FieldType_unknown;
    }
}

// ****************************************************************************
// Method: VolumeAttributes::GetFieldTypeName
//
// Purpose:
//   This method returns the name of a field type given its index.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   Tue Mar 13 14:48:06 PST 2007
//
// Modifications:
//
// ****************************************************************************

std::string
VolumeAttributes::GetFieldTypeName(int index) const
{
    switch (index)
    {
        case 0:  return "bool";
        case 1:  return "bool";
        case 2:  return "att";
        case 3:  return "float";
        case 4:  return "bool";
        case 5:  return "att";
        case 6:  return "int";
        case 7:  return "variablename";
        case 8:  return "ucharArray";
        case 9:  return "bool";
        case 10:  return "float";
        case 11:  return "bool";
        case 12:  return "float";
        case 13:  return "bool";
        case 14:  return "float";
        case 15:  return "bool";
        case 16:  return "float";
        case 17:  return "bool";
        case 18:  return "int";
        case 19:  return "enum";
        case 20:  return "enum";
        case 21:  return "int";
        case 22:  return "enum";
        case 23:  return "double";
        case 24:  return "enum";
        default:  return "invalid index";
    }
}

// ****************************************************************************
// Method: VolumeAttributes::FieldsEqual
//
// Purpose:
//   This method compares two fields and return true if they are equal.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   Tue Mar 13 14:48:06 PST 2007
//
// Modifications:
//
// ****************************************************************************

bool
VolumeAttributes::FieldsEqual(int index_, const AttributeGroup *rhs) const
{
    int i;

    const VolumeAttributes &obj = *((const VolumeAttributes*)rhs);
    bool retval = false;
    switch (index_)
    {
    case 0:
        {  // new scope
        retval = (legendFlag == obj.legendFlag);
        }
        break;
    case 1:
        {  // new scope
        retval = (lightingFlag == obj.lightingFlag);
        }
        break;
    case 2:
        {  // new scope
        retval = (colorControlPoints == obj.colorControlPoints);
        }
        break;
    case 3:
        {  // new scope
        retval = (opacityAttenuation == obj.opacityAttenuation);
        }
        break;
    case 4:
        {  // new scope
        retval = (freeformFlag == obj.freeformFlag);
        }
        break;
    case 5:
        {  // new scope
        retval = (opacityControlPoints == obj.opacityControlPoints);
        }
        break;
    case 6:
        {  // new scope
        retval = (resampleTarget == obj.resampleTarget);
        }
        break;
    case 7:
        {  // new scope
        retval = (opacityVariable == obj.opacityVariable);
        }
        break;
    case 8:
        {  // new scope
        // Compare the freeformOpacity arrays.
        bool freeformOpacity_equal = true;
        for(i = 0; i < 256 && freeformOpacity_equal; ++i)
            freeformOpacity_equal = (freeformOpacity[i] == obj.freeformOpacity[i]);

        retval = freeformOpacity_equal;
        }
        break;
    case 9:
        {  // new scope
        retval = (useColorVarMin == obj.useColorVarMin);
        }
        break;
    case 10:
        {  // new scope
        retval = (colorVarMin == obj.colorVarMin);
        }
        break;
    case 11:
        {  // new scope
        retval = (useColorVarMax == obj.useColorVarMax);
        }
        break;
    case 12:
        {  // new scope
        retval = (colorVarMax == obj.colorVarMax);
        }
        break;
    case 13:
        {  // new scope
        retval = (useOpacityVarMin == obj.useOpacityVarMin);
        }
        break;
    case 14:
        {  // new scope
        retval = (opacityVarMin == obj.opacityVarMin);
        }
        break;
    case 15:
        {  // new scope
        retval = (useOpacityVarMax == obj.useOpacityVarMax);
        }
        break;
    case 16:
        {  // new scope
        retval = (opacityVarMax == obj.opacityVarMax);
        }
        break;
    case 17:
        {  // new scope
        retval = (smoothData == obj.smoothData);
        }
        break;
    case 18:
        {  // new scope
        retval = (samplesPerRay == obj.samplesPerRay);
        }
        break;
    case 19:
        {  // new scope
        retval = (rendererType == obj.rendererType);
        }
        break;
    case 20:
        {  // new scope
        retval = (gradientType == obj.gradientType);
        }
        break;
    case 21:
        {  // new scope
        retval = (num3DSlices == obj.num3DSlices);
        }
        break;
    case 22:
        {  // new scope
        retval = (scaling == obj.scaling);
        }
        break;
    case 23:
        {  // new scope
        retval = (skewFactor == obj.skewFactor);
        }
        break;
    case 24:
        {  // new scope
        retval = (sampling == obj.sampling);
        }
        break;
    default: retval = false;
    }

    return retval;
}

///////////////////////////////////////////////////////////////////////////////
// User-defined methods.
///////////////////////////////////////////////////////////////////////////////

// ****************************************************************************
//  Method:  VolumeAttributes::ChangesRequireRecalculation
//
//  Modifications:
//    Jeremy Meredith, Thu Oct  2 13:27:54 PDT 2003
//    Let changes in rendererType to force a recalculation.  This is
//    appropriate since the 3D texturing renderer prefers different
//    dimensions (i.e. powers of two) than the splatting renderer.
//
//    Hank Childs, Mon Dec 15 14:42:26 PST 2003
//    Recalculate if the smooth option was hit.
//
//    Hank Childs, Mon Nov 22 09:37:12 PST 2004
//    Recalculate if the ray trace button was hit.
//
//    Brad Whitlock, Wed Dec 15 09:31:24 PDT 2004
//    Removed doSoftware since it's now part of rendererType.
//
//    Kathleen Bonnell, Thu Mar  3 09:27:40 PST 2005
//    Recalculate if scaling or skewFactor changed for RayCasting.
//
// ****************************************************************************
bool
VolumeAttributes::ChangesRequireRecalculation(const VolumeAttributes &obj) const
{
    if (opacityVariable != obj.opacityVariable)
        return true;
    if (resampleTarget != obj.resampleTarget)
        return true;
    if (rendererType != obj.rendererType)
        return true;
    if (smoothData != obj.smoothData)
        return true;

    if (rendererType == VolumeAttributes::RayCasting)
    {
        if (scaling != obj.scaling)
            return true;
        if (scaling == VolumeAttributes::Skew && skewFactor != obj.skewFactor)
            return true;
    }

    return false;
}

// ****************************************************************************
//  Method:  VolumeAttributes::GradientWontChange
//
//  Purpose:
//    Determines if the gradient can avoid being invalidated.
//
//  Arguments:
//    obj        the attributes to compare with
//
//  Programmer:  Jeremy Meredith
//  Creation:    September 30, 2003
//
//  Modifications:
//    Jeremy Meredith, Thu Oct  2 13:30:29 PDT 2003
//    Added rendererType and gradientType to the list of modifications
//    that require re-calculating the gradient.
//
// ****************************************************************************
bool
VolumeAttributes::GradientWontChange(const VolumeAttributes &obj) const
{
    int i;

    // Compare the freeformOpacity arrays.
    bool freeformOpacity_equal = true;
    for(i = 0; i < 256 && freeformOpacity_equal; ++i)
        freeformOpacity_equal = (freeformOpacity[i] == obj.freeformOpacity[i]);

    // Create the return value
    return ((freeformFlag         == obj.freeformFlag) &&
            (opacityControlPoints == obj.opacityControlPoints) &&
            (resampleTarget       == obj.resampleTarget) &&
            (opacityVariable      == obj.opacityVariable) &&
            freeformOpacity_equal &&
            (useColorVarMin       == obj.useColorVarMin) &&
            (colorVarMin          == obj.colorVarMin) &&
            (useColorVarMax       == obj.useColorVarMax) &&
            (colorVarMax          == obj.colorVarMax) &&
            (useOpacityVarMin     == obj.useOpacityVarMin) &&
            (opacityVarMin        == obj.opacityVarMin) &&
            (useOpacityVarMax     == obj.useOpacityVarMax) &&
            (opacityVarMax        == obj.opacityVarMax) &&
            (rendererType         == obj.rendererType) &&
            (gradientType         == obj.gradientType));
}


// ****************************************************************************
// Method: VolumeAttributes::GetTransferFunction
//
// Purpose:
//   This method calculates the transfer function and stores it in the rgba
//   array that is passed in.
//
// Programmer: Brad Whitlock
// Creation:   Tue Aug 21 15:44:34 PST 2001
//
// Modifications:
//   Brad Whitlock, Thu Nov 21 15:05:25 PST 2002
//   GetColors has been moved to ColorControlPointList. I updated this code
//   to take that into account.
//
//   Jeremy Meredith, Thu Oct  2 13:29:40 PDT 2003
//   Made the method const.
//
// ****************************************************************************

void
VolumeAttributes::GetTransferFunction(unsigned char *rgba) const
{
    unsigned char rgb[256 * 3];
    unsigned char alphas[256];
    const unsigned char *a_ptr;

    // Figure out the colors
    colorControlPoints.GetColors(rgb, 256);
    // Figure out the opacities
    if(freeformFlag)
        a_ptr = freeformOpacity;
    else
    {
        GetGaussianOpacities(alphas);
        a_ptr = alphas;
    }

    unsigned char *rgb_ptr = rgb;
    unsigned char *rgba_ptr = rgba;
    for(int i = 0; i < 256; ++i)
    {
        // Copy the color
        *rgba_ptr++ = *rgb_ptr++;
        *rgba_ptr++ = *rgb_ptr++;
        *rgba_ptr++ = *rgb_ptr++;
        // Copy the alpha
        *rgba_ptr++ = *a_ptr++;
    }
}

// ****************************************************************************
// Method: VolumeAttributes::SetDefaultColorControlPoints
//
// Purpose:
//   This method replaces all of the color control points in the list with the
//   default color control points.
//
// Programmer: Brad Whitlock
// Creation:   Tue Aug 21 15:44:34 PST 2001
//
// Modifications:
//
// ****************************************************************************

void
VolumeAttributes::SetDefaultColorControlPoints()
{
    const float positions[] = {0., 0.25, 0.5, 0.75, 1.};
    const unsigned char colors[5][4] = {
        {0,   0,   255, 255},
        {0,   255, 255, 255},
        {0,   255, 0,   255},
        {255, 255, 0,   255},
        {255, 0,   0,   255}};

    // Clear the color control point list.
    colorControlPoints.ClearControlPoints();

    // Set the default control points in the color control point list.
    for(int i = 0; i < 5; ++i)
    {
        ColorControlPoint cpt;
        cpt.SetPosition(positions[i]);
        cpt.SetColors(colors[i]);
        colorControlPoints.AddControlPoints(cpt);
    }
    SelectColorControlPoints();
}

// ****************************************************************************
// Method: VolumeAttributes::GetGaussianOpacities
//
// Purpose:
//   This method calculates the opacities using the object's gaussian control
//   point list and stores the results in the alphas array that is passed in.
//
// Arguments:
//   alphas : The return array for the colors.
//
// Programmer: Brad Whitlock
// Creation:   Thu Sep 6 10:23:59 PDT 2001
//
// Modifications:
//    Jeremy Meredith, Thu Oct  2 13:30:00 PDT 2003
//    Made the method const.
//
// ****************************************************************************
void
VolumeAttributes::GetGaussianOpacities(unsigned char *alphas) const
{
    int i;
    float values[256];
    for (i=0; i<256; i++)
        values[i] = 0.;

    for (int p=0; p<opacityControlPoints.GetNumControlPoints(); p++)
    {
        const GaussianControlPoint &pt =
                               opacityControlPoints.GetControlPoints(p);
        float pos    = pt.GetX();
        float width  = pt.GetWidth();
        float height = pt.GetHeight();
        float xbias  = pt.GetXBias();
        float ybias  = pt.GetYBias();
        for (i=0; i<256; i++)
        {
            float x = float(i)/float(256-1);

            // clamp non-zero values to pos +/- width
            if (x > pos+width || x < pos-width)
            {
                values[i] = (values[i] > 0.) ? values[i] : 0.;
                continue;
            }

            // non-zero width
            if (width == 0)
                width = .00001;

            // translate the original x to a new x based on the xbias
            float x0;
            if (xbias==0 || x == pos+xbias)
            {
                x0 = x;
            }
            else if (x > pos+xbias)
            {
                if (width == xbias)
                    x0 = pos;
                else
                    x0 = pos+(x-pos-xbias)*(width/(width-xbias));
            }
            else // (x < pos+xbias)
            {
                if (-width == xbias)
                    x0 = pos;
                else
                    x0 = pos-(x-pos-xbias)*(width/(width+xbias));
            }

            // center around 0 and normalize to -1,1
            float x1 = (x0-pos)/width;

            // do a linear interpolation between:
            //    a gaussian and a parabola        if 0<ybias<1
            //    a parabola and a step function   if 1<ybias<2
            float h0a = exp(-(4*x1*x1));
            float h0b = 1. - x1*x1;
            float h0c = 1.;
            float h1;
            if (ybias < 1)
                h1 = ybias*h0b + (1-ybias)*h0a;
            else
                h1 = (2-ybias)*h0b + (ybias-1)*h0c;
            float h2 = height * h1;

            // perform the MAX over different guassians, not the sum
            values[i] = (values[i] > h2) ? values[i] : h2;
        }
    }

    // Convert to unsigned char and return.
    for(i = 0; i < 256; ++i)
    {
        int tmp = int(values[i] * 255.);
        if(tmp < 0)
            tmp = 0;
        else if(tmp > 255)
            tmp = 255;
        alphas[i] = (unsigned char)(tmp);
    }
}

void
VolumeAttributes::GetOpacities(unsigned char *alphas)
{
    if(freeformFlag)
    {
        for(int i = 0; i < 256; ++i)
            alphas[i] = freeformOpacity[i];
    }
    else
        GetGaussianOpacities(alphas);
}

void
VolumeAttributes::SetSmoothingFlag(bool val)
{
    colorControlPoints.SetSmoothingFlag(val);
    Select(2, (void *)&colorControlPoints);
}

bool
VolumeAttributes::GetSmoothingFlag() const
{
    return colorControlPoints.GetSmoothingFlag();
}

void
VolumeAttributes::SetEqualSpacingFlag(bool val)
{
    colorControlPoints.SetEqualSpacingFlag(val);
    Select(2, (void *)&colorControlPoints);
}

bool
VolumeAttributes::GetEqualSpacingFlag() const
{
    return colorControlPoints.GetEqualSpacingFlag();
}

}
