#ifndef _SF_SCALAR_FIELD_
#define _SF_SCALAR_FIELD_

#include <Inventor/fields/SoSubField.h>
#include <Inventor/SbLinear.h>

//////////////////////////////////////////////////////////////////////////////
//
//  Class: SFScalarField
//
//  Field for maintaining scalar fields of multiple dimensions.  It offers
//  the ability to add a data field to an Inventor node or engine so that the
//  Database detects when it has been updated.  It is very similar to the
//  SoSFImage field, except for one major difference.  It also has an option in
//  the setValue() function for copying the data or not.  This is very useful
//  when setting a field from an Engine.  It can greatly improve the
//  performance time of interactive tools.
//
//  The copy option works by either copying all the data or just saving the
//  pointer to the data.  Of course this will only work if the memory the
//  pointer references isn't deleted.
//
//////////////////////////////////////////////////////////////////////////////

class SFScalarField : public SoSField {

  // Inventor defined macros for subclassing SoSField
  SO_SFIELD_REQUIRED_HEADER(SFScalarField);
  SO_SFIELD_CONSTRUCTOR_HEADER(SFScalarField);
#if HAVE_COIN
  PRIVATE_SFIELD_IO_HEADER();
#else
  SO__SFIELD_RW_HEADER(SFScalarField);
#endif

public:
  static void  initClass ();

  // set the dimensions, number of dimensions, number of field components and
  // the pointer to the field, triggers a valueChanged() to Inventor
  virtual void setValue (const int dm[3], float *ptr, bool copyField=true);
  // get the field value, triggers an evaluate() to Inventor
  float *      getValue (int dm[3]) const;
  float *      startEditing (int dm[3]);
  void         finishEditing ();
  
  // the following functions do not trigger any Inventor calls
  float *      getDataPtr       () const {return data;}
  const int *  getDims          () const {return dims;}
  int          getNumValues     () const {return numValues;}
  bool         getDataCopied    () const {return dataCopied;}
  void         getMinMax        (float &min, float &max) const;
  void         setSize          (const int dm[3]);

  int operator == (const SFScalarField &d) const;
  int operator != (const SFScalarField &d) const
                    { return !((*this) == d); }

protected:
  // used to maintain the dimensions of the field
  int  dims[3];

  // current number of values being managed, this is the product of all the
  // dimension values
  int     numValues;
  // pointer to data
  float  *data;

private:
  // used to determine if the data was copied over to this field or if this
  // field just points to it somewhere else
  bool    dataCopied;
  
  // whenever the field is copied space is allocated.  this variable is used
  // to keep track of how many bytes have been allocated.  This way if field
  // of the same or smaller size needs to be copied, we don't need to
  // allocate more memory.
  int     valuesAllocated;
  
  // pointer to allocated array.
  float   *myData;
};

#endif /* _SF_SCALAR_FIELD */
