/* NODEGEN/vrml.h */

/* This vrml.H header file, as well as the other files in the NODEGEN
 * directory that also are present in the main VRML/ directory are different
 * of those in the main directory for two reasons:
 * 1) we want to isolate node generation code as much as possible from
 * already implemented node code.
 * 2) node generation requires some other data that is not needed in the
 * node implementations itself and vice versa: the node implementations need
 * data that is not needed for node code generation. */

#ifndef _VRML_H_
#define _VRML_H_

#include "error.H"

/* VRML'97 field Types */
typedef enum fieldType {
  tdummy,
  tSFBool, tSFString, tSFInt32, tSFFloat, tSFTime, tSFVec2f, tSFVec3f, tSFColor, tSFRotation, tSFImage, tSFNode,
  tMFBool, tMFString, tMFInt32, tMFFloat, tMFTime, tMFVec2f, tMFVec3f, tMFColor, tMFRotation, tMFImage, tMFNode
} fieldType;

#ifndef __cplusplus

/* exact declaration not needed nor wanted in the plain C code of 
 * lex.l and error.c */
typedef void *fieldValueBase[2];
typedef void SFNode, MFNode, MFString;

#else /* _cplusplus */
#include <iostream.h>

/* ***************************** simple types ***************************** */
// Only basic constructors and convertors to the nearest standard type are provided.
// Use builtin C++ types or your own vector .... classes (with appropriate 
// own type convertor) for computations.

class SFBool {
  bool val;
public:
  inline SFBool(int b =false) 		{ val = b; }
  inline operator bool()   		{ return val; }
  friend ostream& operator<<(ostream& s, SFBool& v) 	{ return s << (v.val ? "TRUE" : "FALSE"); }
  friend ostream& operator<<(ostream& s, SFBool* v) 	{ return v ? operator<<(s, *v) : (s << "NULL"); }
};

class SFString {
  char *val;
public:
  inline SFString(char *s =0) 		{ val = s; }
  inline operator char*() 		{ return val; }
  friend ostream& operator<<(ostream& s, SFString& v) { return s << v.val; }
  friend ostream& operator<<(ostream& s, SFString* v) 	{ return v ? operator<<(s, *v) : (s << "NULL"); }
};

class SFInt32 {
  int val;
public:
  inline SFInt32(int d =0) 		{ val = d; }
  inline operator int() 		{ return val; }
  friend ostream& operator<<(ostream& s, SFInt32& v) 	{ return s << v.val; }
  friend ostream& operator<<(ostream& s, SFInt32* v) 	{ return v ? operator<<(s, *v) : (s << "NULL"); }
};

class SFFloat {
  float val;
public:
  inline SFFloat(float f =0.) 		{ val = f; }
  inline operator float() 		{ return val; }
  friend ostream& operator<<(ostream& s, SFFloat& v) 	{ return s << v.val; }
  friend ostream& operator<<(ostream& s, SFFloat* v) 	{ return v ? operator<<(s, *v) : (s << "NULL"); }
};

class SFTime {
  double val;
public:
  inline SFTime(double f =0.) 		{ val = f; }
  inline operator double() 		{ return val; }
  friend ostream& operator<<(ostream& s, SFTime& v) 	{ return s << v.val; }
  friend ostream& operator<<(ostream& s, SFTime* v) 	{ return v ? operator<<(s, *v) : (s << "NULL"); }
};

struct SFVec2f {
  float s, t;
  inline SFVec2f(float ss =0., float tt =0.) { s = ss; t = tt; }
  friend ostream& operator<<(ostream& s, SFVec2f& v) 	{ return s << v.s << ' ' << v.t; }
  friend ostream& operator<<(ostream& s, SFVec2f* v) 	{ return v ? operator<<(s, *v) : (s << "NULL"); }
};

struct SFVec3f {
  float x, y, z;
  inline SFVec3f(float xx =0., float yy =0., float zz =0.) { x=xx; y=yy; z=zz; }
  friend ostream& operator<<(ostream& s, SFVec3f& v) 	{ return s << v.x << ' ' << v.y << ' ' << v.z; }
  friend ostream& operator<<(ostream& s, SFVec3f* v) 	{ return v ? operator<<(s, *v) : (s << "NULL"); }
};

struct SFColor {
  float	r, g, b;
  inline SFColor(float rr =0., float gg =0., float bb =0.) { r=rr; g=gg; b=bb; }
  friend ostream& operator<<(ostream& s, SFColor& v) 	{ return s << v.r << ' ' << v.g << ' ' << v.b; }
  friend ostream& operator<<(ostream& s, SFColor* v) 	{ return v ? operator<<(s, *v) : (s << "NULL"); }
};

struct SFRotation {
  float x, y, z, radians;
  inline SFRotation(float xx =0., float yy =0., float zz =0., float rad =0.) { x=xx; y=yy; z=zz, radians=rad; }
  friend ostream& operator<<(ostream& s, SFRotation& v) 	{ return s << v.x << ' ' << v.y << ' ' << v.z << ' ' << v.radians; }
  friend ostream& operator<<(ostream& s, SFRotation* v) 	{ return v ? operator<<(s, *v) : (s << "NULL"); }
};

class SFImage {
  void construct(int w, int h, int n, unsigned int *pix);
  void destruct(void);

public:
  int width, height, num_components;
  unsigned int *pixels;

  SFImage(unsigned int w =0, unsigned int h =0, unsigned int n =0, unsigned int *pix =0);
  SFImage(const SFImage& src);
  SFImage& operator=(const SFImage& src);
  ~SFImage();

  friend ostream& operator<<(ostream&, SFImage&);
  friend ostream& operator<<(ostream& s, SFImage* im) { return im ? operator<<(s, *im) : (s << "NULLL"); }
};

// SFNode class is defined at the bottom of this file as we first need to define
// a couple of other types on which SFNode builds.

/* ***************************** array types ***************************** */
#include "Array.H"

typedef array<SFBool> 		MFBool;
typedef array<SFString> 	MFString;
typedef array<SFInt32> 		MFInt32;
typedef array<SFFloat> 		MFFloat;
typedef array<SFTime> 		MFTime;
typedef array<SFVec2f> 		MFVec2f;
typedef array<SFVec3f> 		MFVec3f;
typedef array<SFColor> 		MFColor;
typedef array<SFRotation> 	MFRotation;
typedef array<SFImage> 		MFImage;
// MFNode is defined at the bottom of this file, after SFNode

/* ***************************** field value union ***************************** */
// for printing field type.names, implemented in fieldValue.C
extern char *fieldTypeName(const fieldType& type);
inline ostream& operator<<(ostream& s, fieldType& v) { return s << fieldTypeName(v); }

// a fieldValue type without constructors, so it can be used in
// unions, such as the yacc stack type (see yacc.y).
struct fieldValueBase {
public:
  // union of pointers to classes that represent VRML field values.
  union {
    void *anyValue;

    SFBool *sfboolValue;
    SFString *sfstringValue;
    SFInt32 *sfint32Value;
    SFFloat *sffloatValue;
    SFTime *sftimeValue;
    SFVec2f *sfvec2fValue;
    SFVec3f *sfvec3fValue;
    SFColor *sfcolorValue;
    SFRotation *sfrotationValue;
    SFImage *sfimageValue;
    class SFNode **sfnodeValue;	   // sfnodeValue is a pointer to an SFNode *

    MFBool *mfboolValue;
    MFString *mfstringValue;
    MFInt32 *mfint32Value;
    MFFloat *mffloatValue;
    MFTime *mftimeValue;
    MFVec2f *mfvec2fValue;
    MFVec3f *mfvec3fValue;
    MFColor *mfcolorValue;
    MFRotation *mfrotationValue;
    MFImage *mfimageValue;
    class MFNode *mfnodeValue;
  };

  // value type (tSFBool etc...)
  fieldType type;

  // checks whether value is of given type (done before assignements e.g.)
  int check(fieldType typ) {
    if (typ != type) {
      Error("fieldValueBase::check", "type conflict (%s,%s)",
	    fieldTypeName(typ), fieldTypeName(type));
      return 0;
    } else
      return 1;
  }

public:
  friend ostream& operator<<(ostream&, fieldValueBase&);
};

class fieldValue: public fieldValueBase {
private:
  void do_assign(fieldValue& v);
  void do_duplicate(fieldValue& v);

public:
  // constructors
  fieldValue(fieldType typ =tdummy, void* value =0) { type = typ; anyValue = value; }
  fieldValue(const fieldValueBase& val) { type = val.type; anyValue = val.anyValue; }

  // the following constructors construct a fieldValue object from a 
  // SFBool ... pointer.
  fieldValue(SFBool *val) 	{ type = tSFBool; sfboolValue = val; }
  fieldValue(SFInt32 *val) 	{ type = tSFInt32; sfint32Value = val; }
  fieldValue(SFString *val) 	{ type = tSFString; sfstringValue = val; }
  fieldValue(SFFloat *val) 	{ type = tSFFloat; sffloatValue = val; }
  fieldValue(SFTime *val) 	{ type = tSFTime; sftimeValue = val; }
  fieldValue(SFVec2f *val) 	{ type = tSFVec2f; sfvec2fValue = val; }
  fieldValue(SFVec3f *val) 	{ type = tSFVec3f; sfvec3fValue = val; }
  fieldValue(SFColor *val) 	{ type = tSFColor; sfcolorValue = val; }
  fieldValue(SFRotation *val) 	{ type = tSFRotation; sfrotationValue = val; }
  fieldValue(SFImage *val) 	{ type = tSFImage; sfimageValue = val; }
  fieldValue(SFNode **val) 	{ type = tSFNode; sfnodeValue = val; }
  fieldValue(MFBool *val) 	{ type = tMFBool; mfboolValue = val; }
  fieldValue(MFInt32 *val) 	{ type = tMFInt32; mfint32Value = val; }
  fieldValue(MFString *val) 	{ type = tMFString; mfstringValue = val; }
  fieldValue(MFFloat *val) 	{ type = tMFFloat; mffloatValue = val; }
  fieldValue(MFTime *val) 	{ type = tMFTime; mftimeValue = val; }
  fieldValue(MFVec2f *val) 	{ type = tMFVec2f; mfvec2fValue = val; }
  fieldValue(MFVec3f *val) 	{ type = tMFVec3f; mfvec3fValue = val; }
  fieldValue(MFColor *val) 	{ type = tMFColor; mfcolorValue = val; }
  fieldValue(MFRotation *val) 	{ type = tMFRotation; mfrotationValue = val; }
  fieldValue(MFImage *val) 	{ type = tMFImage; mfimageValue = val; }
  fieldValue(MFNode *val) 	{ type = tMFNode; mfnodeValue = val; }

  // assginement operator: no type checking and only the value pointer is 
  // copied. See assign(), duplicate() and instantiate() below if the 
  // object pointed to needs to be copied or duplicated.
  fieldValue& operator=(const fieldValue& val)
  { anyValue = val.anyValue; type = val.type; return *this; }

#ifdef NEVER
  fieldValue& operator=(SFBool *val)
  { check(tSFBool); sfboolValue = val; return *this; }
  fieldValue& operator=(SFString *val)
  { check(tSFString); sfstringValue = val; return *this; }
  fieldValue& operator=(SFInt32 *val) 	
  { check(tSFInt32); sfint32Value = val; return *this; }
  fieldValue& operator=(SFFloat *val) 	
  { check(tSFFloat); sffloatValue = val; return *this; }
  fieldValue& operator=(SFTime *val) 	
  { check(tSFTime); sftimeValue = val; return *this; }
  fieldValue& operator=(SFVec2f *val) 
  { check(tSFVec2f); sfvec2fValue = val; return *this; }
  fieldValue& operator=(SFVec3f *val) 
  { check(tSFVec3f); sfvec3fValue = val; return *this; }
  fieldValue& operator=(SFColor *val) 
  { check(tSFColor); sfcolorValue = val; return *this; }
  fieldValue& operator=(SFRotation *val) 
  { check(tSFRotation); sfrotationValue = val; return *this; }
  fieldValue& operator=(SFImage *val) 
  { check(tSFImage); sfimageValue = val; return *this; }
  fieldValue& operator=(SFNode **val)
  { check(tSFNode); sfnodeValue = val; return *this; }
  fieldValue& operator=(MFBool *val)
  { check(tMFBool); mfboolValue = val; return *this; }
  fieldValue& operator=(MFString *val) 	
  { check(tMFString); mfstringValue = val; return *this; }
  fieldValue& operator=(MFInt32 *val) 	
  { check(tMFInt32); mfint32Value = val; return *this; }
  fieldValue& operator=(MFFloat *val) 	
  { check(tMFFloat); mffloatValue = val; return *this; }
  fieldValue& operator=(MFTime *val) 	
  { check(tMFTime); mftimeValue = val; return *this; }
  fieldValue& operator=(MFVec2f *val) 
  { check(tMFVec2f); mfvec2fValue = val; return *this; }
  fieldValue& operator=(MFVec3f *val) 
  { check(tMFVec3f); mfvec3fValue = val; return *this; }
  fieldValue& operator=(MFColor *val) 
  { check(tMFColor); mfcolorValue = val; return *this; }
  fieldValue& operator=(MFRotation *val) 
  { check(tMFRotation); mfrotationValue = val; return *this; }
  fieldValue& operator=(MFImage *val) 
  { check(tMFImage); mfimageValue = val; return *this; }
  fieldValue& operator=(MFNode *val)
  { check(tMFNode); mfnodeValue = val; return *this; }
#endif

  // type convertors: retrieve type and value pointer.
  operator fieldType()  { return type; }
  operator void*()      { return anyValue; }

  // type convertors (cast a fieldValue to a SFBool pointer etc...)
  operator SFBool*() 	{ check(tSFBool); return sfboolValue; }
  operator SFString*() 	{ check(tSFString); return sfstringValue; }
  operator SFInt32*() 	{ check(tSFInt32); return sfint32Value; }
  operator SFFloat*() 	{ check(tSFFloat); return sffloatValue; }
  operator SFTime*() 	{ check(tSFTime); return sftimeValue; }
  operator SFVec2f*() 	{ check(tSFVec2f); return sfvec2fValue; }
  operator SFVec3f*() 	{ check(tSFVec3f); return sfvec3fValue; }
  operator SFColor*() 	{ check(tSFColor); return sfcolorValue; }
  operator SFRotation*(){ check(tSFRotation); return sfrotationValue; }
  operator SFImage*() 	{ check(tSFImage); return sfimageValue; }
  operator SFNode**() 	{ check(tSFNode); return sfnodeValue; }
  operator MFBool*() 	{ check(tMFBool); return mfboolValue; }
  operator MFString*() 	{ check(tMFString); return mfstringValue; }
  operator MFInt32*() 	{ check(tMFInt32); return mfint32Value; }
  operator MFFloat*() 	{ check(tMFFloat); return mffloatValue; }
  operator MFTime*() 	{ check(tMFTime); return mftimeValue; }
  operator MFVec2f*() 	{ check(tMFVec2f); return mfvec2fValue; }
  operator MFVec3f*() 	{ check(tMFVec3f); return mfvec3fValue; }
  operator MFColor*() 	{ check(tMFColor); return mfcolorValue; }
  operator MFRotation*(){ check(tMFRotation); return mfrotationValue; }
  operator MFImage*() 	{ check(tMFImage); return mfimageValue; }
  operator MFNode*() 	{ check(tMFNode); return mfnodeValue; }

  // value retrieval: return (a reference to) the SFBool ... value pointed to
  operator SFBool&() 	{ check(tSFBool); return *sfboolValue; }
  operator SFString&() 	{ check(tSFString); return *sfstringValue; }
  operator SFInt32&() 	{ check(tSFInt32); return *sfint32Value; }
  operator SFFloat&() 	{ check(tSFFloat); return *sffloatValue; }
  operator SFTime&() 	{ check(tSFTime); return *sftimeValue; }
  operator SFVec2f&() 	{ check(tSFVec2f); return *sfvec2fValue; }
  operator SFVec3f&() 	{ check(tSFVec3f); return *sfvec3fValue; }
  operator SFColor&() 	{ check(tSFColor); return *sfcolorValue; }
  operator SFRotation&(){ check(tSFRotation); return *sfrotationValue; }
  operator SFImage&() 	{ check(tSFImage); return *sfimageValue; }
  operator SFNode*&() 	{ check(tSFNode); return *sfnodeValue; }
  operator MFBool&() 	{ check(tMFBool); return *mfboolValue; }
  operator MFString&() 	{ check(tMFString); return *mfstringValue; }
  operator MFInt32&() 	{ check(tMFInt32); return *mfint32Value; }
  operator MFFloat&() 	{ check(tMFFloat); return *mffloatValue; }
  operator MFTime&() 	{ check(tMFTime); return *mftimeValue; }
  operator MFVec2f&() 	{ check(tMFVec2f); return *mfvec2fValue; }
  operator MFVec3f&() 	{ check(tMFVec3f); return *mfvec3fValue; }
  operator MFColor&() 	{ check(tMFColor); return *mfcolorValue; }
  operator MFRotation&(){ check(tMFRotation); return *mfrotationValue; }
  operator MFImage&() 	{ check(tMFImage); return *mfimageValue; }
  operator MFNode&(); // implemented after MFNode class declaration

  // the following methods assign, duplicate and swap the values pointed to
  // by sf*Value. Watch out: especially for SFImage values, assignment or
  // duplication may require copying of large amounts of data.

  // checks the type and assigns the object pointed to by src.
  // - this->*Value remains the same
  // - if the type is tSFNode, only the pointer to the node is assigned.
  //   (src and this will point to the same SFNode).
  // - this->*Value and src.*Value must not be nil.
  void assign(fieldValue& src);

  // duplicates *src.*Value ands let this->*Value point to the duplicate. 
  // - this->*Value gets a new value
  // - If the type is tSFNode, only the pointer to the node is duplicated.
  //   that means: a new SFNode* is created and initialized with 
  //   *src.sfnodeValue (which can be NULL).
  // - this->*Value can be nil, but src.*Value must not be nil
  void duplicate(fieldValue& src);
  void duplicate(void) { duplicate(*this); }

  // creates a new instance of the object pointed to by 'this' and lets
  // this->*Value point to the new instance. This member function is
  // identical to duplicate(void), except if the type is tSFNode or tMFNode.
  // If the type is tSFNode or tMFNode, the node(s) is(are) replaced
  // by new node instances w.r.t. the master node. (see SFNode::instantiate()).
  void instantiate(class Proto *master =0);

  // if (this->*Value is not nil) assign(); else duplicate(). Used to
  // do assignements if it is not certain that the destination (this)
  // has already been initialized.
  void assign_or_duplicate_if_nil(fieldValue& src);
};

extern fieldValue default_fieldValue(fieldType);

/* ********************** node interface declaration ********************** */

typedef enum interfaceKind {kdummy, keventIn, kexposedField, kfield, keventOut} interfaceKind;
extern char *interfaceKindName(const interfaceKind& kind);
inline ostream& operator<<(ostream& s, interfaceKind& v) { return s << interfaceKindName(v); }

class interfaceDeclaration {
  void construct(interfaceKind k, fieldType t, char *id, fieldValue val, class redirection *r);
  void destruct(void);
  void do_synchronize(void);

public:
  interfaceKind kind;	// field, exposedField, eventIn or eventOut
  fieldType type;	// value type (SFBool ...)
  char *Id;		// id name of field ...
  fieldValue value;	// points to the actual value

  // node class Ids if type is SFNode or MFNode
  char* nodeClassId;
  SFNode *nodeClass;

  // points to corresponding (EXTERN)PROTO interface field or event 
  // (IS statement in PROTO scene graph node value declaration).
  // This could be avoided by letting 'value' be a reference to the
  // PROTO interface value, but that would create problems concerning
  // PROTO instantiation.
  class redirection *ref;

  // -1 when constructed, 0 when initialized by initialize(), incremented
  // at each assignement. Can be used to keep track of whether the value 
  // has been updated or not.
  long clock;

  // if checkval is not nil, it shall be a pointer to a function that is 
  // called after an assignement to check the validity of the assigned value.
  // If valid, it shall return 'true', if not valid, it shall print an
  // warning or error message, restore a default value and return 'false'.
  bool (*checkval)(fieldValue& value);

  // constructors and destructor
  interfaceDeclaration(interfaceKind k=kdummy, fieldType t=tdummy, char* id=0);
  interfaceDeclaration(interfaceKind k, fieldType t, char* id, fieldValue val);
  interfaceDeclaration(const interfaceDeclaration& src);
  interfaceDeclaration& operator=(const interfaceDeclaration& src);
  ~interfaceDeclaration(void);

  // initializes a field (with a value read from a VRML file). clock is
  // set to 0.
  void initialize(fieldValue& val);

  // replaces value by a new instance
  void instantiate(class Proto *master =0);

  // assigns the value to the field. If the field is a synonym for some other
  // field, that other field is assigned the value to as well.
  // clock is incremented.
  void assign(fieldValue& val);

  // lets the field or event be a synonym of the field or event 'decl' of
  // the specified node (e.g. IS statement in PROTO scene graph node
  // value declaration).
  void redirect(SFNode *node, interfaceDeclaration *decl =0);

  // if the interface declaration is a redirection (by using the IS
  // statement in VRML file), and the clock values differ, meaning
  // that one of both this value of to value referred to has been updated,
  // the value referred to and its clock value are copied to 'this'.
  void synchronize(void)
  {
    if (ref) do_synchronize();    
  }

  friend ostream& operator<<(ostream&, interfaceDeclaration&);
};

/* ***************************** SFNode class **************************** */
class SFNode {
protected:
  virtual void construct (const char *id, const int nr, const interfaceDeclaration *iface);
  virtual void destruct(void);
  virtual void instantiate_interface(Proto *master =0);

public:
  const char *typeId, *nameId;	// if not 0, nameId is name of DEF'ed node or 0
  int nameIndex;		// if not -1, index of DEF'ed node in namedNodes table

  // nr of events/fields and their description
  int nrInterfaceDeclarations;
  interfaceDeclaration *interface;

  // parent class Ids and pointers */
  array<char*> parentClassIds;
  array<SFNode*> parentNodes;
  array<SFNode*> dependNodes;

  // is this node a super node class description?
  bool isParent;

  // filename and lineno when the node was created.
  char *filename;
  int line;
  
  // initialized to 0, incremented each time a value of the node is updated.
  long clock;

  // user data.
  union {
    long i;
    void *p;
  } client_data;

  // constructors and destructor
  SFNode(const char* id =0, const int nr =0, const interfaceDeclaration* iface =0);
  SFNode(const SFNode& src);
  SFNode& operator=(const SFNode& src);
  virtual ~SFNode();

  // the following routines look up the field, eventIn, eventOut with given Id 
  // in the interface of the current node. NULL is returned if not found.
  interfaceDeclaration* get_field(char *fieldId);
  interfaceDeclaration* get_eventIn(char *eventInId);
  interfaceDeclaration* get_eventOut(char *eventOutId);

  // composes a unique name identifying the node, for debugging etc...
  virtual char* name(char* buf =0);

  // Creates and returns an instance of 'this', basically a copy of 'this'
  // with it's own interface and field/event redirections resolved to
  // the interface of the Proto node that is passed (if one is passed)
  // as an argument.
  virtual SFNode* instantiate(class Proto *master =0);

  // Returns a pointer to the first node of nodes scene graph. The first node
  // is the node itself if it is a builtin node and the first node of the PROTO
  // scene graph if it is a PROTO node (see Proto.H). Used for PROTO node resolution.
  virtual SFNode *firstnode(void) { return this; }

  // Some interface members may be synonym of enclosing PROTO interface members.
  // Nodes can also store (stricktly spoken redudant) data, derived from the
  // interface member values (e.g.: PROTO-resolved children node pointers).
  // The synchronize member function will take care that the node's state is
  // made consistent again after some potential changes (e.g. eventIns).
  // Children node graphs are traversed. This function should be called for
  // the world's root nodes before rendering each frame.
  virtual void synchronize(void)
  {
    for (int i=0; i<nrInterfaceDeclarations; i++) 
      interface[i].synchronize();
  }

  // The actual rendering of a node is accomplished by renderer class methods
  // (see renderer.H). This node class method will call the appropriate renderer
  // method(s) for the node. Children node graphs are traversed as well. This node
  // class method should be called for every root node in the world in order to
  // render a frame.
  virtual void render(void);

  // prints the nodes contents. For debugging etc... (overloadable function)
  virtual ostream& print(ostream& s =cout);

  friend ostream& operator<<(ostream& s, SFNode& v) { return v.print(s); }
  friend ostream& operator<<(ostream& s, SFNode* v) { return v ? operator<<(s,*v) : (s << "NULL"); }
};

/* ***************************** MFNode class ***************************** */
class MFNode: public array<SFNode *> {
public:
  inline MFNode(int len =0, SFNode **table =0) { if (len>0) init(len, table); }

  //
  inline void render(void) { for (int i=0; i<size; i++) { s[i]->render(); } }
  inline void synchronize(void) { for (int i=0; i<size; i++) { s[i]->synchronize(); } }

  // returns a new MFNode with instances of the contained SFNodes
  MFNode *instantiate(class Proto *master =0);

  // copies 'this' to 'result', replacing PROTO's by the first node in their
  // scene graph (see SFNode::firstnode() 
  void firstnodes(array<SFNode*> *result);
};

// couldn't be implemented before because class MFNode needs to be known.
inline fieldValue::operator MFNode&() { check(tMFNode); return *mfnodeValue; }

#include "./Proto.H"

#endif /*__cplusplus*/

#endif /*_VRML_H_*/

