5.10. Special Behavior for Derived Elements

In Inventor, elements that do not have a derived class have only a static set() method. Elements with derived classes for their GL versions often have both a static set() method and a setElt() method. Using this mechanism, nodes can deal with the generic base class for elements without dealing individually with each subclass. For example, a node's doAction() method can simply call SoDrawStyleElement::set rather than calling SoGLDrawStyleElement::set. If you are deriving an element from an existing element class, or if you are creating a new hierarchy of element classes, the setElt() mechanism described here may prove useful.

Suppose you are writing a new renderer and need some elements to perform additional work. In this case, you can derive an element from the existing element. You write a virtual setElt() method for your new derived class that sets the element to its correct value and performs the desired side effects. The rest is C++ magic, as follows:

  1. The static set() method of the base class calls its virtual setElt() method.

  2. If there is no derived class, the setElt() method of the base class is called. If there is a derived class, the setElt() method of the derived class is called to set the element value.

In Open Inventor, this mechanism is used for the GL rendering version of certain elements. Let's take a closer look at the plain vanilla and GL versions of the draw-style element to illustrate this process. As noted in Section 5.2, “Deriving a Class from an Existing Element”, the GL version is used to perform side effects required for GL rendering. The base class, SoDrawStyleElement SoDrawStyleElement SoDrawStyleElement , provides a static set() method that calls a virtual setElt() on the modifiable instance of the element:

// Sets draw style in element accessed from state.
void
SoDrawStyleElement::set(SoState *state, SoNode *node, Style
                        style)
{
   SoDrawStyleElement *elt;

   // Get an instance we can change (pushing if necessary)
   elt = (SoDrawStyleElement *)
             getElement(state, classStackIndex,node);

   if (elt != NULL)
      elt->setElt(style);      // virtual setElt()--see below
}

The virtual setElt() is defined in the base class as follows:

SoLongElement::setElt( long value )
{
   data = value;
}

The derived GL class, SoGLDrawStyleElement SoGLDrawStyleElement SoGLDrawStyleElement , redefines the virtual setElt() method to do two things:

  • It sets the value in the Inventor instance of the element.

  • It makes the proper calls to OpenGL (glPolygonMode()) to reflect the current state.

The code for the setElt() method in SoGLDrawStyleElement SoGLDrawStyleElement SoGLDrawStyleElement is as follows:

// Sets draw style in element.
void
SoGLDrawStyleElement::setElt(long value)
if (data != value) {
   data = value;
   send();       // The send() method calls glPolygonMode().
}

At the same time, SoGLDrawStyleElement SoGLDrawStyleElement SoGLDrawStyleElement inherits the static set() method from the parent class, SoDrawStyleElement SoDrawStyleElement SoDrawStyleElement . Note that you can derive other classes from SoDrawStyleElement SoDrawStyleElement SoDrawStyleElement in a similar way to support other rendering actions.