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(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; // 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_ 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_ eventIns: one for each exposedField member of the node. For example: // set_ 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_ 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_ 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_ functions: // eventOuts: // SFBool isActive; void post_isActive(const SFBool& val); SFTime time; void post_time(const SFTime& val); Use the post_ 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_ 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 _is_updated and _clear_update routines can be used in order to keep track of dynamic changes in an environment being rendered. Use _is_updated() in order to inspect whether the member has been updated since the last call to _clear_update(). A field member is updated each time it gets assigned a new value (with assign_ or set_). An eventOut is updated each time post_ 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