Polymorphism is the ability of ports to expose multiple data types. A more advanced implementation technique is needed for handling port polymorphism during the evaluation of a custom ICENode. Since the type resolution will occur at connection time, the coding of the ICENode must be done in a generic way to support multiple data types. The recommended approach is to query the ICENodeContext object for the current output port types and to use a template class to delegate the evaluation.
The following code snippet is part of the SDK example which demonstrates this technique for both 1D and 2D-arrays:
// CEvaluator class is handling the most common types. The data is copied by reference, // this is the most optimal way of setting output ports with input ports. template < class T > class CEvaluator { public: static void Do( ICENodeContext& in_ctxt, ULONG in_nInPortID, XSI::siICENodeStructureType in_outStruct ) { if ( in_outStruct == XSI::siICENodeStructureSingle ) { CDataArray<T> outData( in_ctxt ); outData.CopyFrom( in_nInPortID ); } else if ( in_outStruct == XSI::siICENodeStructureArray ) { CDataArray2D<T> outData( in_ctxt ); outData.CopyFrom( in_nInPortID ); } } }; // Special case for the custom data type template <> class CEvaluator< CDataArrayCustomType::TData > { public: static void Do( ICENodeContext& in_ctxt, ULONG in_nInPortID, XSI::siICENodeStructureType in_outStruct ) { if ( in_outStruct == XSI::siICENodeStructureSingle ) { CDataArrayCustomType outData( in_ctxt ); outData.CopyFrom( in_nInPortID ); } else if ( in_outStruct == XSI::siICENodeStructureArray ) { CDataArray2DCustomType outData( in_ctxt ); outData.CopyFrom( in_nInPortID ); } } }; SICALLBACK CustomPassThrough_Evaluate( ICENodeContext& in_ctxt ) { ULONG out_portID = in_ctxt.GetEvaluatedOutputPortID( ); switch( out_portID ) { case ID_OUT : { XSI::siICENodeDataType outPortType; XSI::siICENodeStructureType outPortStruct; XSI::siICENodeContextType outPortContext; in_ctxt.GetPortInfo( ID_OUT, outPortType, outPortStruct, outPortContext ); switch( outPortType ) { case siICENodeDataFloat: CEvaluator<float>::Do( in_ctxt, ID_IN, outPortStruct ); break; case siICENodeDataLong: CEvaluator<LONG>::Do( in_ctxt, ID_IN, outPortStruct ); break; case siICENodeDataBool: CEvaluator<bool>::Do( in_ctxt, ID_IN, outPortStruct ); break; case siICENodeDataVector2: CEvaluator<MATH::CVector2f>::Do( in_ctxt, ID_IN, outPortStruct ); break; case siICENodeDataVector3: CEvaluator<MATH::CVector3f>::Do( in_ctxt, ID_IN, outPortStruct ); break; case siICENodeDataVector4: CEvaluator<MATH::CVector4f>::Do( in_ctxt, ID_IN, outPortStruct ); break; case siICENodeDataQuaternion: CEvaluator<MATH::CQuaternionf>::Do( in_ctxt, ID_IN, outPortStruct ); break; case siICENodeDataRotation: CEvaluator<MATH::CRotationf>::Do( in_ctxt, ID_IN, outPortStruct ); break; case siICENodeDataMatrix33: CEvaluator<MATH::CMatrix3f>::Do( in_ctxt, ID_IN, outPortStruct ); break; case siICENodeDataMatrix44: CEvaluator<MATH::CMatrix4f>::Do( in_ctxt, ID_IN, outPortStruct ); break; case siICENodeDataColor4: CEvaluator<MATH::CColor4f>::Do( in_ctxt, ID_IN, outPortStruct ); break; case siICENodeDataShape: CEvaluator<MATH::CShape>::Do( in_ctxt, ID_IN, outPortStruct ); break; case siICENodeDataCustomType: CEvaluator<CDataArrayCustomType::TData>::Do( in_ctxt, ID_IN, outPortStruct ); break; }; } break; }; return CStatus::OK; } The next example shows another approach to handle port polymorphism when output arrays need to be set by index (memory allocation is required): // Another version of the CEvaluator class that copies data by allocating memory. template < class T > class CCopyEvaluator { public: static void Do( ICENodeContext& in_ctxt, ULONG in_nInPortID, XSI::siICENodeStructureType in_outStruct ) { CIndexSet indexSet( in_ctxt ); if ( in_outStruct == XSI::siICENodeStructureSingle ) { CDataArray<T> outData( in_ctxt ); CDataArray<T> inData( in_ctxt, in_nInPortID ); for(CIndexSet::Iterator it = indexSet.Begin(); it.HasNext(); it.Next()) { outData[it] = inData[it]; } } else if ( in_outStruct == XSI::siICENodeStructureArray ) { CDataArray2D<T> outData( in_ctxt ); CDataArray2D<T> inData( in_ctxt, in_nInPortID ); for(CIndexSet::Iterator it = indexSet.Begin(); it.HasNext(); it.Next()) { typename CDataArray2D<T>::Accessor inAccess = inData[it]; typename CDataArray2D<T>::Accessor outAccess = outData.Resize( it, inAccess.GetCount() ); memcpy( &outAccess[0], &inAccess[0], outAccess.GetCount() ); } } } }; // Special case for the bool type template <> class CCopyEvaluator< bool > { public: static void Do( ICENodeContext& in_ctxt, ULONG in_nInPortID, XSI::siICENodeStructureType in_outStruct ) { CIndexSet indexSet( in_ctxt ); if ( in_outStruct == XSI::siICENodeStructureSingle ) { CDataArray<bool> outData( in_ctxt ); CDataArray<bool> inData( in_ctxt, in_nInPortID ); for(CIndexSet::Iterator it = indexSet.Begin(); it.HasNext(); it.Next()) { outData.Set( it, inData[it] ); } } else if ( in_outStruct == XSI::siICENodeStructureArray ) { CDataArray2D<bool> outData( in_ctxt ); CDataArray2D<bool> inData( in_ctxt, in_nInPortID ); for(CIndexSet::Iterator it = indexSet.Begin(); it.HasNext(); it.Next()) { CDataArray2D<bool>::Accessor inAccess = inData[it]; CDataArray2D<bool>::Accessor outAccess = outData.Resize( it, inAccess.GetCount() ); for ( ULONG i=0; i<outAccess.GetCount(); i++ ) { outAccess.Set( i, inAccess[i] ); } } } } }; // Special case for the custom data type template <> class CCopyEvaluator< CDataArrayCustomType::TData > { public: static void Do( ICENodeContext& in_ctxt, ULONG in_nInPortID, XSI::siICENodeStructureType in_outStruct ) { if ( in_outStruct == XSI::siICENodeStructureSingle ) { CDataArrayCustomType outData( in_ctxt ); CDataArrayCustomType inData( in_ctxt, in_nInPortID ); CIndexSet indexSet( in_ctxt ); for(CIndexSet::Iterator it = indexSet.Begin(); it.HasNext(); it.Next()) { ULONG nSize; const XSI::CDataArrayCustomType::TData* pInData; inData.GetData(it, &pInData, nSize); XSI::CDataArrayCustomType::TData* pOutData = outData.Resize(it, nSize); ::memcpy( pOutData, pInData, nSize ); } } else if ( in_outStruct == XSI::siICENodeStructureArray ) { CDataArray2DCustomType outData( in_ctxt ); CDataArray2DCustomType inData( in_ctxt, in_nInPortID ); CIndexSet indexSet( in_ctxt ); for (CIndexSet::Iterator it = indexSet.Begin(); it.HasNext(); it.Next()) { CDataArray2DCustomType::Accessor inAccess = inData[ it ]; CDataArray2DCustomType::Accessor outAccess = outData.Resize( it, inAccess.GetCount( ) ); for ( ULONG i=0; i<outAccess.GetCount(); i++ ) { CDataArray2DCustomType::TData* pInData = NULL; ULONG nSize; inAccess.GetData( i, &pInData, nSize ); CDataArray2DCustomType::TData* pOutData = outAccess.Resize( i, nSize ); ::memcpy( pOutData, pInData, nSize ); } } } } };