This file describes the XRML node class API. You need this API when
writing a renderer. Each renderer callback function receives as an
argument a pointer to a node to be rendered. This file explains,
among other things, how to read the nodes state, how to post
eventOuts while rendering and how to keep track of dynamic changes
in a virtual world.


The API of a node consists of three parts:

- An automatically generated part containing members to manage
the nodes state as defined in the VRML'97 specifications or in the
input scripts to the nodegen program. It has the same structure
for all nodes.

- An optional specific part, differing from node class
to node class. This part typically contains utility functions for
renderers (for instance, keeping a 4x4 matrix representation for
Transform nodes). This part is implemented manually.

- A common part, inherited by all nodes from the SFNode
class declared in xrml.H.



Node state maintainance:
=======================

The API for every (leaf) node contains:

- an Is<nodeclass>(SFNode*) routine to check whether an SFNode* 
is a pointer to a node of the given class. For instance:

  extern bool IsBillboard(SFNode*);

- int major_version(void), and int minor_version(void) functions
return the major and minor version of the node, as generated
with nodegen. This is used in the parser in order to detect
potentially out-dated node implementations (there should be no
such out-dated code, but you never know one day, when there
will be run-time loadable node classes e.g.)

- bool is_leaf_class(void): returns whether of not the node is
a lead node class or a base node class. The nodes state is only
completely available for leaf nodes. Parent node classes only
contain part of the state shared by subclasses. A XRML input
file can only contain leaf nodes.

- constructors and destructor, SFNode* instantiate(Proto*),
void render(void): not of interest to the renderer programmer.

- state variables: name and type correspond exactly to the
field and exposedField state values described in the VRML'97
specifications (or nodegen input scripts), with one exception:
MFNode values are arrays of the proper node class, and
SFNode values are also of the proper class for the field
(for instance Material* for SFNode material field of Appearance 
node).

Example:

  // state values:
  // Do not assign directly unless you know very well what you are doing.
  SFVec3f          	axisOfRotation;
  //  array<Children*> 	children;
  //  SFVec3f          	bboxCenter;
  //  SFVec3f          	bboxSize;

The values that are commented out are declared in a parent 
class.

These values can be read at any time and they can be assigned 
to or even deleted if you know what you are doing:
. no value range checking
. no update bit is set
. no eventOuts are generated (when applicable)
. deleting or changing some variables of some nodes may confuse
(and crash) the default renderer callback functions.
Except in very rare cases where you really don't want to do so, 
you should use the assignement functions described below, in 
particular the set_<exposedField> functions for exposedFields.

- a list of eventIns: for example

  // eventIns:
  void             	addChildren(const MFNode&);
  void             	removeChildren(const MFNode&);
  
Just call these functions in order to send the node an eventIn
data message.

- a list of set_<exposedField> eventIns: one for each 
exposedField member of the node. For example:

  // set_<exposedField> eventIns: with forwarding and eventOut generation
  void             	set_axisOfRotation(const SFVec3f&);
  void             	set_children(const MFNode&);

Use these functions in order to assign a value to an exposedField.
The assignement value is properly forwarded to linked
exposedFields in a PROTO node implementation (if any) and
eventOuts are generated appropriately. After succesful assignement,
the exposedField is marked as "has been updated" (see below).

- a list of assign_<field> functions: for instance

  // field assignement: no forwarding or eventOut generation!
  bool             	assign_axisOfRotation(const SFVec3f&);
  bool             	assign_children(const MFNode&);
  bool             	assign_bboxCenter(const SFVec3f&);
  bool             	assign_bboxSize(const SFVec3f&);
  
These routines assign a new value to a field or exposedField.
The field is marked as "has been updated", but no eventOuts
are generated and neither is there any assignement to linked
fields in a PROTO implementation. For exposedFields, you should
use the set_<exposedField> functions instead. For fields: fields
are not supposed to change value after initialisation. This
routine allows to break this rule if you really need to.

- a list of eventOut values and post_<eventOut> functions:

  // eventOuts:
  //  SFBool            	isActive;
  void             	post_isActive(const SFBool& val);
  SFTime            	time;
  void             	post_time(const SFTime& val);

Use the post_<eventOut> functions with proper argument in order
to post an eventOut from the node. The eventOut is routed to
conencted eventIns (if any) next time the world::newframe()
function is called. The latest posted value can
be read from the corresponding eventOut member variable, which
acts as temporary storage for the posted value. The variable may
appear commented out in the header file. This is the case if 
the variable is declared for a parent node. In order to override
the posted value before calling world::newframe for instance
in scripts (no scripting language binding has been implemented 
so far [PhB 21-feb-2001]), simply call the post_<eventOut> 
function a second time with the new value to be posted.

- update status bit inspection and clear functions for each
field, exposedField and eventOut:

  // update status
  inline bool      	cycleInterval_is_updated(void) { return (status & cycleInterval_updated); }
  inline void      	cycleInterval_clear_update(void) { status &= ~cycleInterval_updated; }
  inline bool      	enabled_is_updated(void) { return (status & enabled_updated); }
  inline void      	enabled_clear_update(void) { status &= ~enabled_updated; }

The <member>_is_updated and <member>_clear_update routines can
be used in order to keep track of dynamic changes in an environment
being rendered.

Use <member>_is_updated() in order to inspect whether the member
has been updated since the last call to <member>_clear_update().
A field member is updated each time it gets assigned a new value 
(with assign_<field> or set_<exposedField>). An eventOut is
updated each time post_<eventOut> is called for the eventOut.

All nodes also have a bool is_updated(void) and void clear_update(void)
member, that can be used in order to inspect whether any of the nodes
fields or eventOuts have been updated, or in order to reset all flags
in one call (see below, general node members).


This part of the API is automatically generated, using the
nodegen program. The current description corresponds to
nodegen 0.5, february 2001.



Utility variables and routines:
==============================

Utility members are declared after the

  // utility members
  
comment in the header file.

They differ from node to node and, until more documentation
is available, a programmer will rely on the documentation provided
in the form of comments in the nodes header file. 

Note for node programmers:
-------------------------

By default, a utility constructor void util_init(void),
copy constructor void util_copy(void) and destructor
void util_destruct(void) are provided as protected node
class member functions. These member functions shall be used
in order to initialise utility variables and to dispose of their
memory when the node gets destructed.



General node members:
====================

These are members that all nodes inherit from the SFNode base class,
declared in xrml.H.

- const char* typeId: e.g. "Viewpoint", etc...

- const char* nameId: nameId of named nodes, or null for ordinary
  nodes.

- char *filename; int line: file name and line nr at the time the
  node has been created. Filled in by the importer. Note: not all
  importers can fill in these data, so don't rely too much on it.

- class world* world: the world the node belongs to

- char* name(char* buf =0): constructs a descriptive name for the node,
  consisting of the typeId, nameId (if not null), filename and line nr.

- bool is_updated(void): returns whether any of the fields or eventOuts
  of the node have been updated since the last time the node update
  flags have been completely cleared

- void clear_update(void): clears all update flags in one call

- client_data data, import_data, export_data: hooks for attaching your
  own data to a node. client_data is a union (also declared in xrml.H):

  typedef union {
    int i;
    void *p;
  } client_data;

  'import_data' and 'export_data' are used by importers and exporters.
  'data' can be used freely in renderers. These client data are initialised
  to null. After using them, clear them using the void clear(client_data)
  function also declared in xrml.H

Note: SFNode contains other members, not described here. They
are for internal use in the library. Don't touch them unless you
know very well what you are doing.



Note on XRML data types:
=======================

The standard data types (SFTime, SFRotation, SFVec3f, SFNode,
MFImage, MFNode, ...) are declared in the header file xrml.H,
which is automatically included in all node class header files.
The MFType types are array templates instantiated for the
SFType types. The array implementation is in Array.H. All data
types need to be converted to standard types (for instance:
SFTime -> double) or to your own data types (for instance
SFVec3f to your own 3D vector class) in order to perform
computations.

Other template classes besides array are:
. associative arrays (Assoc.H)
. stacks (Stack.H)
. linked lists (List.H)
Some day, someone should convince me to use the standard
template library (or something else) instead of these custom
implemented data types.



Philippe Bekaert

February 21, 2001