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