2.8. Using New Node Classes

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.8, “ 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 SoFieldContainer SoFieldContainer , from which SoNode SoNode SoNode 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.7.  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();
}


Example 2.8.  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
   }
}