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