Softimage SDK Programmer's Guide > Customizing Softimage using the SDK > Custom ICENodes > Custom ICENode Categories >

# Element Generator Custom ICENodes

Element generator nodes are like regular custom ICENodes with the additional capability to define the number of elements to process during an evaluation. For now, this feature can only be used to generate particles. The element generator capability is enabled by setting one or more output ports context to siICENodeContextElementGenerator during the ICENode registration phase. The siICENodeContextElementGenerator context is not compatible with other contexts and must be the only one specified.

Some simple registration rules must be followed when defining the element generator ports:

1. All input ports must be defined with a singleton context (siICENodeContextSingleton).

2. All output ports must be defined with a siICENodeContextSingleton or siICENodeContextElementGenerator.

If these rules are not met, Softimage will log an error at registration time and then abort the ICENode registration.

The number of elements to process must be specified in the BeginEvaluate callback with MDNodeContext::PutNumberOfElementsToProcess. Exceptionally, accessing input port data from the BeginEvaluate callback is supported for generator nodes. Softimage issues an error if the BeginEvaluate callback is missing.

The following ICENode example demonstrates the element generator feature by generating a 2D particle grid:

    #include <xsi_application.h>
    #include <xsi_context.h>
    #include <xsi_pluginregistrar.h>
    #include <xsi_status.h>
    #include <xsi_mdnodecontext.h>
    #include <xsi_mdnodedef.h>
    #include <xsi_factory.h>
    #include <xsi_math.h>
    #include <xsi_vector3f.h>
    #include <xsi_indexset.h>
    #include <xsi_dataarray.h>

    // Defines port, group and map identifiers used for registering the ICENode
    enum IDs
    {
    	ID_Size = 1,
    	ID_G_100 = 100,
    	ID_Vector3D = 200,
    	ID_Elements = 201,
    	ID_TMAP = 400,
    	ID_SMAP,
    	ID_CMAP,
    	ID_UNDEF = ULONG_MAX
    };

    using namespace XSI;

    XSIPLUGINCALLBACK CStatus XSILoadPlugin( PluginRegistrar& in_reg )
    {
    	in_reg.PutAuthor(L"Softimage");
    	in_reg.PutName(L"ICENodeGenerator Plugin");
    	in_reg.PutVersion(1,0);
    	ICENodeDef nodeOpDef;
    	nodeOpDef = Application().GetFactory().CreateICENodeDef( L"ICENodeGenerator" );
    	CStatus st;

    	// Add a port to specify the size of the grid to generate
    	st = nodeOpDef.AddPortGroup(ID_G_100);
    	st.AssertSucceeded( ) ;

    	st = nodeOpDef.AddInputPort(
    		ID_Size, // port index
    		ID_G_100, // group index
    		siICENodePortDataLong, // data type
    		siICENodePortStructureSingle, // structure type
    		siICENodeContextSingleton, // context type
    		L"Size", // port name
    		L"Size", // port scripting name
    		10			// default value
    	);
    	st.AssertSucceeded( ) ;

    	// Add output ports.
    	st = nodeOpDef.AddOutputPort(
    		ID_Vector3D, // port index
    		siICENodeDataVector3, // data type
    		siICENodePortStructureSingle, // structure type
    		siICENodeContextElementGenerator, // context type
    		L"OutVector3D", // port name
    		L"OutVector3D"// port scripting name
    	);
    	st.AssertSucceeded( ) ;

    	st = nodeOpDef.AddOutputPort(
    		ID_Elements, // port index
    		siICENodePortDataLong, // data type
    		siICENodePortStructureSingle, // structure type
    		siICENodeContextSingleton, // context type
    		L"Elements", // port name
    		L"Elements 				"// port scripting name
    	);
    	st.AssertSucceeded( ) ;

    	PluginItem nodeItem = in_reg.RegisterICENode(nodeOpDef);
    	nodeItem.PutCategories(L"Custom ICENode");

    	return CStatus::OK;
    }
    XSIPLUGINCALLBACK CStatus ICENodeGenerator_BeginEvaluate( ICENodeContext& in_ctxt )
    {
    	CDataArrayLong inSize( in_ctxt, ID_Size );

    	// Total number of elements to generate
    	ULONG nSize = inSize[ 0 ];
    	ULONG nElements = nSize * nSize;
    	in_ctxt.PutNumberOfElementsToProcess( nElements );

    	return CStatus::OK;
    }
    XSIPLUGINCALLBACK CStatus ICENodeGenerator_Evaluate( ICENodeContext& in_ctxt )
    {
    	// The current output port being evaluated...
    	ULONG out_portID = in_ctxt.GetEvaluatedOutputPortID( );

    	switch( out_portID )
    	{
    		case ID_Vector3D:
    		{
    			// Set the output port array with the new elements
    			CDataArrayVector3f outData( in_ctxt );
    			CDataArrayLong inSize( in_ctxt, ID_Size );

    			ULONG nSize = inSize[ 0 ];
    			CIndexSet indexSet( in_ctxt );

    			for(CIndexSet::Iterator it = indexSet.Begin(); it.HasNext(); it.Next())
    			{
    				ULONG nAbsIndex = it.GetAbsoluteIndex( );

    				ULONG x = nAbsIndex % nSize;
    				ULONG y = nAbsIndex / nSize;
    				MATH::CVector3f v;
    				v.PutX( x * 1.0f - nSize/2 );
    				v.PutY( y * 1.0f - nSize/2 );
    				v.PutZ( 0.0f );
    				outData[ it ] = v;
    			}
    		}
    		break;

    		case ID_Elements:
    		{
    			// Returns the number of elements to generate
    			CDataArrayLong outData( in_ctxt );
    			outData[ 0 ] = in_ctxt.GetNumberOfElementsToGenerate( );
    		}
    		break;
    	};

    	return CStatus::OK;
    }