6.9. Creating a New Field Converter

Whenever a connection is made between fields, inputs, or outputs and the types aren't the same, Inventor tries to insert an engine to convert from the source type to the destination type. Inventor maintains a table that lists the class of engine that converts between a given pair of types.

You can define new converters and add them to the table, either to support additional conversions between built-in field types, or to support conversions to or from new fields you have created (see Chapter 3). For convenience, a single class of engine can support several different types of conversions (for example, a single engine may be able to convert from a rational number field to a float, a short, or a long). When Inventor creates an instance of the field converter, it tells it the source and destination field types.

Creating a field converter is similar to creating other types of engines, with a few additional steps. The following checklist summarizes things you need to do when you create a new field converter.

Implement the initClass() method. For each conversion that the engine supports, after the SO_ENGINE_INIT_CLASS() macro, call

SoDB::addConverter(typeIdOfSourceField, typeIdOfDestinationField, YourEngine::getClassTypeId());

If the converter has multiple inputs or outputs, its evaluate() method can check input.isConnected() and output.getNumConnections() to find out which conversion needs to be done. Or, the getInput() and getOutput() methods can save their parameters in instance variables and the evaluate() method can check them.

The getInput() and getOutput() methods check the passed type and return the appropriate input or output. It is guaranteed that Inventor will never call these methods except for pairs of types registered with SoDB::addConverter() .

Example 6.11, “ ConvertSFShortToSFFloat.h ” shows the header file for a new field converter, ConvertSFShortToSFFloat. Example 6.12, “ ConvertSFShortToSFFloat.cxx shows the source code for this class.


Example 6.12.  ConvertSFShortToSFFloat.cxx

#include <Inventor/SoDB.h>
#include "ConvertSFShortToSFFloat.h"

SO_ENGINE_SOURCE(ConvertSFShortToSFFloat);

// Initializes the ConvertSFShortToSFFloat class.
void
ConvertSFShortToSFFloat::initClass()
{
   SO_ENGINE_INIT_CLASS(ConvertSFShortToSFFloat,
                        SoFieldConverter, "FieldConverter");

   // Register this converter's type with the Inventor database
   // to convert from a field (or engine output) of type
   // SoSFShort to a field of type SoSFFloat.
   // We only call this once, since this engine offers only one
   // type conversion.
   SoDB::addConverter(SoSFShort::getClassTypeId(),
                      SoSFFloat::getClassTypeId(),
                      getClassTypeId());
}

void
ConvertSFShortToSFFloat::exitClass()
{
   SoDB::removeConverter(SoSFShort::getClassTypeId(),SoSFFloat::getClassTypeId());
   SO_ENGINE_EXIT_CLASS(ConvertSFShortToSFFloat);
}

// Constructor
ConvertSFShortToSFFloat::ConvertSFShortToSFFloat()
{
   // Do standard constructor tasks
   SO_ENGINE_CONSTRUCTOR(ConvertSFShortToSFFloat);

   // Define input field and its default value
   SO_ENGINE_ADD_INPUT(input,  (0));

   // Define the output, specifying its type
   SO_ENGINE_ADD_OUTPUT(output, SoSFFloat);
}

// Destructor. Does nothing.

ConvertSFShortToSFFloat::~ConvertSFShortToSFFloat()
{
}

// This is the evaluation routine.

void
ConvertSFShortToSFFloat::evaluate()
{
   // Get the input value as a short, convert it to a float, and
   // output it
   float    value = (float) input.getValue();
   SO_ENGINE_OUTPUT(output, SoSFFloat, setValue(value));
}

// This returns the input field for the given type. Since we
// have only one input field, we don't have to check the type.

SoField *
ConvertSFShortToSFFloat::getInput(SoType)
{
   return &input;
}

// This does the same for the output.

SoEngineOutput *
ConvertSFShortToSFFloat::getOutput(SoType)
{
   return &output;
}