Softimage SDK Programmer's Guide > Customizing with the SDK > Custom ICENodes > Custom ICENode Processing >

# Handling Port Polymorphism

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 );
    				}
    			}
    		}
    	}
    };