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:
All input ports must be defined with a singleton context (siICENodeContextSingleton).
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; }