Node classes you have created must be initialized in every application that uses them. Example 2-7 shows how this is done, using the Glow , Pyramid , and Alternate node classes defined in the previous examples. The program reads a file (newNodes.iv, shown in Example 2-8) that has a scene graph containing instances of these nodes. It writes the scene graph to standard output and then opens an examiner viewer to display the graph.
You can see from this example that extender node classes should be initialized after standard classes, which are initialized by SoDB::init(). In this program, SoDB::init() is called by SoXt::init(). Also, base classes must be initialized before any classes derived from them, since the initialization macros for a node class refer to the parent class.
Notice in Example 2.10, “ newNodes.iv ” that the Pyramid and Glow nodes, because they are not built into the Inventor library, write out their field names and types. (The Alternate class has no fields.) See the discussion of the file format for new (unknown) nodes in the section called “File Format for Unknown Nodes and Engines”.
The isBuiltIn flag is a protected variable in SoFieldContainer( C++ | Java | .NET ), from which SoNode( C++ | Java | .NET ) is derived. If this flag is FALSE, field types are written out along with the field values. By default, this flag is FALSE, but all Inventor classes set it to TRUE. If you are building a toolkit that uses Inventor and want your new classes to appear the same as Inventor classes, be sure to set this flag to TRUE.
Example 2.9. NewNodes.c++
#include <Inventor/SoDB.h> #include <Inventor/SoInput.h> #include <Inventor/Xt/SoXt.h> #include <Inventor/Xt/viewers/SoXtExaminerViewer.h> #include <Inventor/actions/SoWriteAction.h> #include <Inventor/nodes/SoSeparator.h> // Header files for new node classes #include "Glow.h" #include "Pyramid.h" #include "Alternate.h" main(int, char **argv) { SoInput myInput; SoSeparator *root; // Initialize Inventor and Xt Widget myWindow = SoXt::init(argv[0]); if (myWindow == NULL) exit(1); // Initialize the new node classes Glow::initClass(); Pyramid::initClass(); Alternate::initClass(); if (! myInput.openFile("newNodes.iv")) { fprintf(stderr, "Can't open \"newNodes.iv\"\n"); return 1; } root = SoDB::readAll(&myInput); if (root == NULL) { printf("File \"newNodes.iv\" contains bad data\n"); return 2; } root->ref(); // Write the graph to stdout SoWriteAction wa; wa.apply(root); // Render it SoXtExaminerViewer *myViewer = new SoXtExaminerViewer(myWindow); myViewer->setSceneGraph(root); myViewer->setTitle("NewNodes"); myViewer->show(); myViewer->viewAll(); SoXt::show(myWindow); SoXt::mainLoop(); root->unref(); delete myViewer; Glow::exitClass(); Pyramid::exitClass(); Alternate::exitClass(); SoXt::finish(); return 0; }
Example 2.10. newNodes.iv
#Inventor V2.0 ascii # # Input file for "newNodes" example program # Separator { Separator { Transform { translation 0 -1.1 0 } Cube { width 10 height .1 depth 10 } } Material { diffuseColor .3 .6 .9 shininess .5 } # Skip every other child Alternate { fields [] Pyramid { fields [SFBitMask parts, SFFloat baseWidth, SFFloat baseDepth, SFFloat height ] } Cube {} # This child is skipped Separator { Glow { fields [SFColor color, SFFloat brightness ] brightness .6 color 1 .3 .3 } Transform { translation 3 .6 0 } Pyramid { fields [SFBitMask parts, SFFloat baseWidth, SFFloat baseDepth, SFFloat height ] height 3.2 } } Sphere {} # This child is skipped } }